feat: adding workspace, session, and message create
This commit is contained in:
parent
1cced7817e
commit
fd00047933
|
|
@ -55,6 +55,7 @@ Per-command scoping (workspace / peer / session) is handled via `-w` / `-p` / `-
|
|||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `honcho workspace list` | List accessible workspaces |
|
||||
| `honcho workspace create <id>` | Create or get a workspace |
|
||||
| `honcho workspace inspect` | Peers, sessions, config for a workspace |
|
||||
| `honcho workspace search <query>` | Search messages across workspace |
|
||||
| `honcho workspace queue-status` | Deriver queue status (filter with `--observer` / `--sender`) |
|
||||
|
|
@ -78,6 +79,7 @@ Per-command scoping (workspace / peer / session) is handled via `-w` / `-p` / `-
|
|||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `honcho session list` | List sessions in the workspace (filter with `--peer/-p`) |
|
||||
| `honcho session create <id>` | Create or get a session (optionally `--peers` to add peers, `--metadata`) |
|
||||
| `honcho session inspect <id>` | Peers, message count, summaries, config |
|
||||
| `honcho session context <id>` | What an agent would see |
|
||||
| `honcho session summaries <id>` | Short + long summaries |
|
||||
|
|
@ -92,6 +94,7 @@ Per-command scoping (workspace / peer / session) is handled via `-w` / `-p` / `-
|
|||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `honcho message list` | List messages in a session (session via `-s` / `HONCHO_SESSION_ID`) |
|
||||
| `honcho message create <content>` | Create a message (requires `--peer/-p`, session via `-s`) |
|
||||
| `honcho message get <id>` | Get a single message (session via `-s` / `HONCHO_SESSION_ID`) |
|
||||
|
||||
### Conclusions (observations)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
"""Message commands: list, get."""
|
||||
"""Message commands: list, get, create."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from typing import Optional
|
||||
|
||||
import typer
|
||||
|
||||
from honcho.api_types import MessageResponse
|
||||
from honcho.api_types import MessageCreateParams, MessageResponse
|
||||
from honcho.http import routes
|
||||
from honcho.message import Message
|
||||
|
||||
from honcho_cli.commands.session import _get_session_id
|
||||
from honcho_cli.commands.workspace import _handle_error
|
||||
from honcho_cli.output import print_result, status
|
||||
from honcho_cli.output import print_error, print_result, status
|
||||
from honcho_cli.validation import validate_resource_id
|
||||
|
||||
from honcho_cli.common import add_common_options, get_client, handle_cmd_flags
|
||||
|
|
@ -87,6 +88,48 @@ def list_messages(
|
|||
_handle_error(e, "message", "list")
|
||||
|
||||
|
||||
@app.command("create")
|
||||
def create_message(
|
||||
content: str = typer.Argument(help="Message content"),
|
||||
peer_id: str = typer.Option(..., "--peer", "-p", help="Peer ID of the message sender"),
|
||||
metadata: Optional[str] = typer.Option(None, "--metadata", help="JSON metadata to associate with the message"),
|
||||
session_id: Optional[str] = typer.Option(None, "--session", "-s", help="Session ID"),
|
||||
workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"),
|
||||
json_output: bool = typer.Option(False, "--json", help="Force JSON output"),
|
||||
) -> None:
|
||||
"""Create a message in a session."""
|
||||
handle_cmd_flags(json_output=json_output, workspace=workspace, session=session_id)
|
||||
sid = _get_session_id(None)
|
||||
validate_resource_id(peer_id, "peer")
|
||||
client, config = get_client()
|
||||
sess = client.session(sid)
|
||||
|
||||
parsed_metadata = None
|
||||
if metadata:
|
||||
try:
|
||||
parsed_metadata = json.loads(metadata)
|
||||
except json.JSONDecodeError as e:
|
||||
print_error("INVALID_JSON", f"--metadata must be valid JSON: {e}", {})
|
||||
raise typer.Exit(1)
|
||||
|
||||
try:
|
||||
msgs = sess.add_messages(MessageCreateParams(
|
||||
peer_id=peer_id,
|
||||
content=content,
|
||||
metadata=parsed_metadata,
|
||||
))
|
||||
msg = msgs[0]
|
||||
print_result({
|
||||
"id": msg.id,
|
||||
"peer_id": msg.peer_id,
|
||||
"content": msg.content,
|
||||
"token_count": msg.token_count,
|
||||
"created_at": str(msg.created_at),
|
||||
})
|
||||
except Exception as e:
|
||||
_handle_error(e, "message", "create")
|
||||
|
||||
|
||||
@app.command("get")
|
||||
def get_message(
|
||||
message_id: str = typer.Argument(help="Message ID"),
|
||||
|
|
|
|||
|
|
@ -60,6 +60,45 @@ def list_sessions(
|
|||
_handle_error(e, "session", "list")
|
||||
|
||||
|
||||
@app.command("create")
|
||||
def create_session(
|
||||
session_id: str = typer.Argument(help="Session ID to create or get"),
|
||||
peers: Optional[str] = typer.Option(None, "--peers", help="Comma-separated peer IDs to add to the session"),
|
||||
metadata: Optional[str] = typer.Option(None, "--metadata", help="JSON metadata to associate with the session"),
|
||||
workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Override workspace ID"),
|
||||
json_output: bool = typer.Option(False, "--json", help="Force JSON output"),
|
||||
) -> None:
|
||||
"""Create or get a session."""
|
||||
handle_cmd_flags(json_output=json_output, workspace=workspace)
|
||||
sid = validate_resource_id(session_id, "session")
|
||||
client, config = get_client()
|
||||
|
||||
parsed_metadata = None
|
||||
if metadata:
|
||||
try:
|
||||
parsed_metadata = json.loads(metadata)
|
||||
except json.JSONDecodeError as e:
|
||||
print_error("INVALID_JSON", f"--metadata must be valid JSON: {e}", {})
|
||||
raise typer.Exit(1)
|
||||
|
||||
peer_ids = [p.strip() for p in peers.split(",") if p.strip()] if peers else []
|
||||
for pid in peer_ids:
|
||||
validate_resource_id(pid, "peer")
|
||||
|
||||
try:
|
||||
sess = client.session(sid, metadata=parsed_metadata)
|
||||
if peer_ids:
|
||||
sess.add_peers(peer_ids)
|
||||
result: dict[str, object] = {"session_id": sess.id}
|
||||
if parsed_metadata is not None:
|
||||
result["metadata"] = parsed_metadata
|
||||
if peer_ids:
|
||||
result["peers"] = peer_ids
|
||||
print_result(result)
|
||||
except Exception as e:
|
||||
_handle_error(e, "session", sid)
|
||||
|
||||
|
||||
@app.command()
|
||||
def inspect(
|
||||
session_id: Optional[str] = typer.Argument(None, help="Session ID (uses default if omitted)"),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"""Workspace commands: list, inspect, delete, search, queue-status."""
|
||||
"""Workspace commands: list, inspect, create, delete, search, queue-status."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Optional
|
||||
|
||||
import typer
|
||||
|
|
@ -62,6 +63,38 @@ def list_workspaces(
|
|||
_handle_error(e, "workspace", "list")
|
||||
|
||||
|
||||
@app.command("create")
|
||||
def create_workspace(
|
||||
workspace_id: str = typer.Argument(help="Workspace ID to create or get"),
|
||||
metadata: Optional[str] = typer.Option(None, "--metadata", help="JSON metadata to associate with the workspace"),
|
||||
json_output: bool = typer.Option(False, "--json", help="Force JSON output"),
|
||||
) -> None:
|
||||
"""Create or get a workspace."""
|
||||
handle_cmd_flags(json_output=json_output)
|
||||
wid = validate_resource_id(workspace_id, "workspace")
|
||||
client, config = get_client(require_workspace=False)
|
||||
ws_client = _with_workspace(client, wid)
|
||||
|
||||
parsed_metadata = None
|
||||
if metadata:
|
||||
try:
|
||||
parsed_metadata = json.loads(metadata)
|
||||
except json.JSONDecodeError as e:
|
||||
print_error("INVALID_JSON", f"--metadata must be valid JSON: {e}", {})
|
||||
raise typer.Exit(1)
|
||||
|
||||
try:
|
||||
# Trigger get-or-create via the workspace ensure mechanism
|
||||
ws_client.get_configuration()
|
||||
result: dict[str, object] = {"workspace_id": wid}
|
||||
if parsed_metadata is not None:
|
||||
ws_client.set_metadata(parsed_metadata)
|
||||
result["metadata"] = parsed_metadata
|
||||
print_result(result)
|
||||
except Exception as e:
|
||||
_handle_error(e, "workspace", wid)
|
||||
|
||||
|
||||
@app.command()
|
||||
def inspect(
|
||||
workspace_id: Optional[str] = typer.Argument(None, help="Workspace ID (uses default if omitted)"),
|
||||
|
|
@ -129,6 +162,13 @@ def delete(
|
|||
client, config = get_client(require_workspace=False)
|
||||
ws_client = _with_workspace(client, workspace_id)
|
||||
|
||||
# Verify workspace exists before prompting for confirmation
|
||||
try:
|
||||
ws_client.get_metadata()
|
||||
except Exception as e:
|
||||
_handle_error(e, "workspace", workspace_id)
|
||||
return
|
||||
|
||||
# Always fetch sessions for dry-run or cascade
|
||||
raw_sessions = _raw_list(ws_client.sessions()) if (dry_run or cascade) else []
|
||||
|
||||
|
|
@ -225,7 +265,7 @@ def _with_workspace(client, workspace_id: str):
|
|||
"""Return a new client pointed at a different workspace."""
|
||||
return Honcho(
|
||||
base_url=str(client.base_url),
|
||||
api_key=client._http._api_key if hasattr(client._http, "_api_key") else None,
|
||||
api_key=client._http.api_key if hasattr(client._http, "api_key") else None,
|
||||
workspace_id=workspace_id,
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue