jvcli 2.0.28__tar.gz → 2.0.30__tar.gz
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.
- {jvcli-2.0.28/jvcli.egg-info → jvcli-2.0.30}/PKG-INFO +1 -1
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/__init__.py +1 -1
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/lib/utils.py +2 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/pages/chat_page.py +25 -18
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/create.py +8 -22
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/server.py +41 -15
- {jvcli-2.0.28 → jvcli-2.0.30/jvcli.egg-info}/PKG-INFO +1 -1
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_server.py +82 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/LICENSE +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/MANIFEST.in +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/README.md +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/api.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/auth.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/cli.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/__init__.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/app.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/lib/__init__.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/lib/page.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/lib/widgets.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/pages/__init__.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/pages/action_dashboard_page.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/pages/analytics_page.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/client/pages/graph_page.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/__init__.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/auth.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/clean.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/client.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/download.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/info.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/publish.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/startproject.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/studio.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/commands/update.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio/assets/index-DDV79SDu.js +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio/assets/index-DdMMONxd.css +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio/index.html +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio/jac_logo.png +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio/tauri.svg +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio/vite.svg +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio-auth/assets/index-Bh6lyeXA.js +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio-auth/assets/index-DdMMONxd.css +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio-auth/index.html +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio-auth/jac_logo.png +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio-auth/tauri.svg +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/studio-auth/vite.svg +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/action_info.yaml +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/agent_descriptor.yaml +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/agent_info.yaml +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/agent_knowledge.yaml +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/agent_memory.yaml +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/project/README.md +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/project/actions/README.md +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/project/daf/README.md +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/project/env.example +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/project/gitignore.example +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/project/globals.jac +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/project/main.jac +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/2.0.0/project/tests/README.md +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/CHANGELOG.md +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/templates/README.md +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli/utils.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli.egg-info/SOURCES.txt +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli.egg-info/dependency_links.txt +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli.egg-info/entry_points.txt +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli.egg-info/requires.txt +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/jvcli.egg-info/top_level.txt +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/setup.cfg +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/setup.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_api.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_auth.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_clean.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_cli.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_create.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_download.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_info.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_publish.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_render_basic.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_startproject.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_studio.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_update.py +0 -0
- {jvcli-2.0.28 → jvcli-2.0.30}/tests/test_utils.py +0 -0
@@ -57,6 +57,7 @@ def call_api(
|
|
57
57
|
json_data: Optional[Dict] = None,
|
58
58
|
files: Optional[List] = None,
|
59
59
|
data: Optional[Dict] = None,
|
60
|
+
timeout: int = 10,
|
60
61
|
) -> Optional[requests.Response]:
|
61
62
|
"""Generic function to call an API endpoint."""
|
62
63
|
|
@@ -77,6 +78,7 @@ def call_api(
|
|
77
78
|
json=json_data,
|
78
79
|
files=files,
|
79
80
|
data=data,
|
81
|
+
timeout=timeout,
|
80
82
|
)
|
81
83
|
|
82
84
|
if response.status_code == 401:
|
@@ -21,9 +21,9 @@ def transcribe_audio(token: str, agent_id: str, file: bytes) -> dict:
|
|
21
21
|
|
22
22
|
data = {
|
23
23
|
"args": "{}",
|
24
|
-
"module_root": "
|
24
|
+
"module_root": "jivas.agent.action",
|
25
25
|
"agent_id": agent_id,
|
26
|
-
"walker": "
|
26
|
+
"walker": "invoke_stt_action",
|
27
27
|
}
|
28
28
|
|
29
29
|
headers = {"Authorization": f"Bearer {token}"}
|
@@ -35,7 +35,6 @@ def transcribe_audio(token: str, agent_id: str, file: bytes) -> dict:
|
|
35
35
|
|
36
36
|
# Parse JSON response
|
37
37
|
result = response.json()
|
38
|
-
|
39
38
|
return result
|
40
39
|
|
41
40
|
|
@@ -47,29 +46,37 @@ def render(router: StreamlitRouter) -> None:
|
|
47
46
|
st.header("Chat", divider=True)
|
48
47
|
tts_on = st.toggle("TTS")
|
49
48
|
|
49
|
+
message = ""
|
50
|
+
# Handle audio input first
|
50
51
|
audio_value = st.audio_input("Record a voice message")
|
51
|
-
|
52
|
-
|
53
|
-
result = transcribe_audio(ctx["token"], selected_agent, audio_value)
|
54
|
-
if result.get("success", False):
|
55
|
-
send_message(
|
56
|
-
result["transcript"], url, ctx["token"], selected_agent, tts_on
|
57
|
-
)
|
52
|
+
# Get selected agent from query params
|
53
|
+
selected_agent = st.query_params.get("agent")
|
58
54
|
|
59
|
-
if selected_agent
|
55
|
+
if selected_agent:
|
60
56
|
chat_messages = st.session_state.messages.get(selected_agent, [])
|
61
57
|
|
62
58
|
# Display chat messages from history on app rerun
|
63
|
-
for
|
64
|
-
|
65
|
-
|
66
|
-
|
59
|
+
for item in chat_messages:
|
60
|
+
role = item.get("role", "user")
|
61
|
+
content = item.get("content", "")
|
62
|
+
with st.chat_message(role):
|
63
|
+
st.markdown(content)
|
64
|
+
if payload := item.get("payload"):
|
67
65
|
with st.expander("...", False):
|
68
66
|
st.json(payload)
|
69
67
|
|
70
|
-
|
71
|
-
|
72
|
-
|
68
|
+
# Process audio input if available
|
69
|
+
if audio_value and selected_agent:
|
70
|
+
result = transcribe_audio(ctx["token"], selected_agent, audio_value)
|
71
|
+
if result and result.get("success", False):
|
72
|
+
message = result["transcript"]
|
73
|
+
|
74
|
+
# Otherwise handle text input
|
75
|
+
if input := st.chat_input("Type your message here"):
|
76
|
+
message = input
|
77
|
+
|
78
|
+
if message:
|
79
|
+
send_message(message, url, ctx["token"], selected_agent, tts_on)
|
73
80
|
|
74
81
|
|
75
82
|
def send_message(
|
@@ -43,14 +43,6 @@ def create() -> None:
|
|
43
43
|
default="No description provided.",
|
44
44
|
help="Description of the action.",
|
45
45
|
)
|
46
|
-
@click.option(
|
47
|
-
"--type",
|
48
|
-
"--type",
|
49
|
-
default="action",
|
50
|
-
type=click.Choice(TYPE_SUFFIX_MAP.keys(), case_sensitive=False),
|
51
|
-
show_default=True,
|
52
|
-
help="Type of the action.",
|
53
|
-
)
|
54
46
|
@click.option(
|
55
47
|
"--singleton",
|
56
48
|
default=True,
|
@@ -58,6 +50,13 @@ def create() -> None:
|
|
58
50
|
show_default=True,
|
59
51
|
help="Indicate if the action is singleton.",
|
60
52
|
)
|
53
|
+
@click.option(
|
54
|
+
"--type",
|
55
|
+
default="action",
|
56
|
+
type=click.Choice(TYPE_SUFFIX_MAP.keys(), case_sensitive=False),
|
57
|
+
show_default=True,
|
58
|
+
help="Type of the action.",
|
59
|
+
)
|
61
60
|
@click.option(
|
62
61
|
"--path",
|
63
62
|
default="./actions",
|
@@ -69,19 +68,6 @@ def create() -> None:
|
|
69
68
|
default=None,
|
70
69
|
help="Namespace for the action. Defaults to the username in the token.",
|
71
70
|
)
|
72
|
-
@click.option(
|
73
|
-
"--singleton",
|
74
|
-
default=True,
|
75
|
-
type=bool,
|
76
|
-
show_default=True,
|
77
|
-
help="Indicate if the action is singleton.",
|
78
|
-
)
|
79
|
-
@click.option(
|
80
|
-
"--path",
|
81
|
-
default="./actions",
|
82
|
-
show_default=True,
|
83
|
-
help="Directory to create the action folder in.",
|
84
|
-
)
|
85
71
|
def create_action(
|
86
72
|
name: str,
|
87
73
|
version: str,
|
@@ -244,7 +230,7 @@ def render(router: StreamlitRouter, agent_id: str, action_id: str, info: dict) -
|
|
244
230
|
\"\"\"
|
245
231
|
|
246
232
|
# Add app header controls
|
247
|
-
(model_key,
|
233
|
+
(model_key, action) = app_header(agent_id, action_id, info)
|
248
234
|
|
249
235
|
# Add app main controls
|
250
236
|
app_controls(agent_id, action_id)
|
@@ -101,23 +101,49 @@ def createadmin(email: Optional[str] = None, password: Optional[str] = None) ->
|
|
101
101
|
if password is None:
|
102
102
|
password = click.prompt("Password", hide_input=True)
|
103
103
|
|
104
|
-
|
105
|
-
f"{os.environ.get('JIVAS_BASE_URL', 'http://localhost:8000')}/user/register"
|
106
|
-
)
|
107
|
-
|
108
|
-
click.echo("Creating system admin...")
|
104
|
+
database_host = os.environ.get("DATABASE_HOST")
|
109
105
|
|
110
|
-
|
111
|
-
|
112
|
-
|
106
|
+
if not database_host:
|
107
|
+
click.echo("Database host is not set. Using signup endpoint...")
|
108
|
+
signup_url = (
|
109
|
+
f"{os.environ.get('JIVAS_BASE_URL', 'http://localhost:8000')}/user/register"
|
113
110
|
)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
111
|
+
|
112
|
+
try:
|
113
|
+
response = requests.post(
|
114
|
+
signup_url, json={"email": email, "password": password}
|
115
|
+
)
|
116
|
+
if response.status_code in (200, 201):
|
117
|
+
click.secho("Admin user created successfully!", fg="green", bold=True)
|
118
|
+
return response.json()
|
119
|
+
else:
|
120
|
+
click.secho(
|
121
|
+
f"Failed to create admin: {response.text}", fg="red", bold=True
|
122
|
+
)
|
123
|
+
except Exception as e:
|
124
|
+
click.secho(
|
125
|
+
f"Error connecting to Jivas Server: {str(e)}", fg="red", bold=True
|
126
|
+
)
|
127
|
+
else:
|
128
|
+
click.echo("Creating system admin...")
|
129
|
+
try:
|
130
|
+
result = subprocess.call(
|
131
|
+
[
|
132
|
+
"jac",
|
133
|
+
"create_system_admin",
|
134
|
+
"main.jac",
|
135
|
+
"--email",
|
136
|
+
email,
|
137
|
+
"--password",
|
138
|
+
password,
|
139
|
+
]
|
140
|
+
)
|
141
|
+
if result == 0:
|
142
|
+
click.secho("Admin user created successfully!", fg="green", bold=True)
|
143
|
+
else:
|
144
|
+
click.secho("Failed to create admin user", fg="red", bold=True)
|
145
|
+
except Exception as e:
|
146
|
+
click.secho(f"Error running jac command: {str(e)}", fg="red", bold=True)
|
121
147
|
|
122
148
|
|
123
149
|
@server.command()
|
@@ -595,6 +595,47 @@ class TestCreateAdminCommand:
|
|
595
595
|
},
|
596
596
|
)
|
597
597
|
|
598
|
+
def test_createadmin_using_jac_command(self, mocker: MockerFixture) -> None:
|
599
|
+
"""Test creating admin user using the jac command."""
|
600
|
+
# Mock subprocess.call successful return
|
601
|
+
mock_subprocess = mocker.patch(
|
602
|
+
"jvcli.commands.server.subprocess.call", return_value=0
|
603
|
+
)
|
604
|
+
|
605
|
+
# Environment with DATABASE_HOST
|
606
|
+
mocker.patch.dict(
|
607
|
+
os.environ,
|
608
|
+
{
|
609
|
+
"DATABASE_HOST": "postgres:5432",
|
610
|
+
"JIVAS_BASE_URL": "http://localhost:8000",
|
611
|
+
},
|
612
|
+
)
|
613
|
+
|
614
|
+
# Run command
|
615
|
+
runner = CliRunner()
|
616
|
+
result = runner.invoke(
|
617
|
+
server,
|
618
|
+
["createadmin", "--email", "admin@example.com", "--password", "admin123"],
|
619
|
+
)
|
620
|
+
|
621
|
+
# Verify behavior
|
622
|
+
assert result.exit_code == 0
|
623
|
+
assert "Creating system admin..." in result.output
|
624
|
+
assert "Admin user created successfully!" in result.output
|
625
|
+
|
626
|
+
# Verify jac command was called
|
627
|
+
mock_subprocess.assert_called_once_with(
|
628
|
+
[
|
629
|
+
"jac",
|
630
|
+
"create_system_admin",
|
631
|
+
"main.jac",
|
632
|
+
"--email",
|
633
|
+
"admin@example.com",
|
634
|
+
"--password",
|
635
|
+
"admin123",
|
636
|
+
]
|
637
|
+
)
|
638
|
+
|
598
639
|
def test_failed_signup_endpoint(self, mocker: MockerFixture) -> None:
|
599
640
|
"""Test behavior when signup endpoint returns an error."""
|
600
641
|
# Mock API error response
|
@@ -619,6 +660,25 @@ class TestCreateAdminCommand:
|
|
619
660
|
assert result.exit_code == 0
|
620
661
|
assert "Failed to create admin: Email already exists" in result.output
|
621
662
|
|
663
|
+
def test_failed_jac_command(self, mocker: MockerFixture) -> None:
|
664
|
+
"""Test behavior when jac command fails."""
|
665
|
+
# Mock subprocess.call failure
|
666
|
+
mocker.patch("jvcli.commands.server.subprocess.call", return_value=1)
|
667
|
+
|
668
|
+
# Environment with DATABASE_HOST
|
669
|
+
mocker.patch.dict(os.environ, {"DATABASE_HOST": "postgres:5432"})
|
670
|
+
|
671
|
+
# Run command
|
672
|
+
runner = CliRunner()
|
673
|
+
result = runner.invoke(
|
674
|
+
server,
|
675
|
+
["createadmin", "--email", "admin@example.com", "--password", "admin123"],
|
676
|
+
)
|
677
|
+
|
678
|
+
# Verify behavior
|
679
|
+
assert result.exit_code == 0
|
680
|
+
assert "Failed to create admin user" in result.output
|
681
|
+
|
622
682
|
def test_createadmin_with_prompts(self, mocker: MockerFixture) -> None:
|
623
683
|
"""Test creating admin with interactive prompts for credentials."""
|
624
684
|
# Mock prompts
|
@@ -678,3 +738,25 @@ class TestCreateAdminCommand:
|
|
678
738
|
# Verify behavior
|
679
739
|
assert result.exit_code == 0
|
680
740
|
assert "Error connecting to Jivas Server: Connection refused" in result.output
|
741
|
+
|
742
|
+
def test_createadmin_jac_command_exception(self, mocker: MockerFixture) -> None:
|
743
|
+
"""Test behavior when jac command raises an exception."""
|
744
|
+
# Mock subprocess to raise an exception
|
745
|
+
mocker.patch(
|
746
|
+
"jvcli.commands.server.subprocess.call",
|
747
|
+
side_effect=Exception("Command not found"),
|
748
|
+
)
|
749
|
+
|
750
|
+
# Environment with DATABASE_HOST
|
751
|
+
mocker.patch.dict(os.environ, {"DATABASE_HOST": "postgres:5432"})
|
752
|
+
|
753
|
+
# Run command
|
754
|
+
runner = CliRunner()
|
755
|
+
result = runner.invoke(
|
756
|
+
server,
|
757
|
+
["createadmin", "--email", "admin@example.com", "--password", "admin123"],
|
758
|
+
)
|
759
|
+
|
760
|
+
# Verify behavior
|
761
|
+
assert result.exit_code == 0
|
762
|
+
assert "Error running jac command: Command not found" in result.output
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|