Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions kittycad.py.patch.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"op": "add",
"path": "/paths/~1file~1conversion/post/x-python",
"value": {
"example": "from kittycad.models.conversion_params import ConversionParams\nfrom kittycad.models.output_format3d import OptionStl\nfrom kittycad.models.system import System\nfrom kittycad.models.axis_direction_pair import AxisDirectionPair\nfrom kittycad.models.axis import Axis\nfrom kittycad.models.direction import Direction\nfrom kittycad.models.axis_direction_pair import AxisDirectionPair\nfrom kittycad.models.axis import Axis\nfrom kittycad.models.direction import Direction\nfrom kittycad.models.selection import OptionSceneByIndex\nfrom kittycad.models.selection import Selection\nfrom kittycad.models.stl_storage import StlStorage\nfrom kittycad.models.unit_length import UnitLength\nfrom kittycad.models.output_format3d import OutputFormat3d\nfrom kittycad.models.input_format3d import OptionInventor\nfrom kittycad.models.system import System\nfrom kittycad.models.axis_direction_pair import AxisDirectionPair\nfrom kittycad.models.axis import Axis\nfrom kittycad.models.direction import Direction\nfrom kittycad.models.axis_direction_pair import AxisDirectionPair\nfrom kittycad.models.axis import Axis\nfrom kittycad.models.direction import Direction\nfrom kittycad.models.input_format3d import InputFormat3d\nfrom pathlib import Path\nfrom typing import Dict\nfrom kittycad._io_types import SyncUpload\nfrom kittycad.models import FileConversion\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_create_file_conversion_options():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n result: FileConversion = client.file.create_file_conversion_options(body=ConversionParams(\n output_format=OutputFormat3d(OptionStl(\n coords=System(\n forward=AxisDirectionPair(\n axis=Axis.Y,\n direction=Direction.POSITIVE,\n ),\n up=AxisDirectionPair(\n axis=Axis.Y,\n direction=Direction.POSITIVE,\n ),\n ),\n selection=Selection(OptionSceneByIndex(\n index=10,\n )),\n storage=StlStorage.ASCII,\n units=UnitLength.CM,\n )),\n src_format=InputFormat3d(OptionInventor(\n coords=System(\n forward=AxisDirectionPair(\n axis=Axis.Y,\n direction=Direction.POSITIVE,\n ),\n up=AxisDirectionPair(\n axis=Axis.Y,\n direction=Direction.POSITIVE,\n ),\n ),\n split_closed_faces=False,\n )),\n ),\n file_attachments={\n \"main.kcl\": Path(\"path/to/main.kcl\"),\n \"helper.kcl\": Path(\"path/to/helper.kcl\"),\n })\n\n\n body: FileConversion = result\n print(body)\n\n",
"example": "from kittycad.models.conversion_params import ConversionParams\nfrom kittycad.models.output_format3d import OptionGltf\nfrom kittycad.models.gltf_presentation import GltfPresentation\nfrom kittycad.models.gltf_storage import GltfStorage\nfrom kittycad.models.output_format3d import OutputFormat3d\nfrom kittycad.models.input_format3d import OptionFbx\nfrom kittycad.models.input_format3d import InputFormat3d\nfrom pathlib import Path\nfrom typing import Dict\nfrom kittycad._io_types import SyncUpload\nfrom kittycad.models import FileConversion\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_create_file_conversion_options():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n result: FileConversion = client.file.create_file_conversion_options(body=ConversionParams(\n output_format=OutputFormat3d(OptionGltf(\n presentation=GltfPresentation.COMPACT,\n storage=GltfStorage.BINARY,\n )),\n src_format=InputFormat3d(OptionFbx()),\n ),\n file_attachments={\n \"main.kcl\": Path(\"path/to/main.kcl\"),\n \"helper.kcl\": Path(\"path/to/helper.kcl\"),\n })\n\n\n body: FileConversion = result\n print(body)\n\n",
"libDocsLink": "https://python.api.docs.zoo.dev/_autosummary/kittycad.KittyCAD.html#kittycad.KittyCAD.file"
}
},
Expand Down Expand Up @@ -771,7 +771,7 @@
"op": "add",
"path": "/paths/~1org~1saml~1idp/post/x-python",
"value": {
"example": "from kittycad.models.saml_identity_provider_create import SamlIdentityProviderCreate\nfrom kittycad.models.idp_metadata_source import OptionUrl\nfrom kittycad.models.idp_metadata_source import IdpMetadataSource\nfrom kittycad.models import SamlIdentityProvider\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_create_org_saml_idp():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n result: SamlIdentityProvider = client.orgs.create_org_saml_idp(body=SamlIdentityProviderCreate(\n idp_entity_id=\"<string>\",\n idp_metadata_source=IdpMetadataSource(OptionUrl(\n url=\"<string>\",\n )),\n technical_contact_email=\"<string>\",\n ))\n\n\n body: SamlIdentityProvider = result\n print(body)\n\n",
"example": "from kittycad.models.saml_identity_provider_create import SamlIdentityProviderCreate\nfrom kittycad.models.idp_metadata_source import OptionBase64EncodedXml\nfrom kittycad.models.base64data import Base64Data\nfrom kittycad.models.idp_metadata_source import IdpMetadataSource\nfrom kittycad.models import SamlIdentityProvider\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_create_org_saml_idp():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n result: SamlIdentityProvider = client.orgs.create_org_saml_idp(body=SamlIdentityProviderCreate(\n idp_entity_id=\"<string>\",\n idp_metadata_source=IdpMetadataSource(OptionBase64EncodedXml(\n data=Base64Data(b\"<bytes>\"),\n )),\n technical_contact_email=\"<string>\",\n ))\n\n\n body: SamlIdentityProvider = result\n print(body)\n\n",
"libDocsLink": "https://python.api.docs.zoo.dev/_autosummary/kittycad.KittyCAD.html#kittycad.KittyCAD.orgs"
}
},
Expand Down Expand Up @@ -1691,23 +1691,23 @@
"op": "add",
"path": "/paths/~1ws~1ml~1copilot/get/x-python",
"value": {
"example": "from kittycad.models import MlCopilotClientMessage\nfrom kittycad.models.ml_copilot_client_message import OptionListModes\nfrom kittycad.models import MlCopilotServerMessage\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_ml_copilot_ws():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n # Connect to the websocket.\n with client.ml.ml_copilot_ws(replay=None,\n conversation_id=None,\n pr=None) as websocket:\n\n # Send a message.\n websocket.send(MlCopilotClientMessage(OptionListModes()))\n\n # Get a message.\n message = websocket.recv()\n print(message)\n\n ",
"example": "from kittycad.models import MlCopilotClientMessage\nfrom kittycad.models.ml_copilot_client_message import OptionProjectContext\nfrom kittycad.models import MlCopilotServerMessage\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_ml_copilot_ws():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n # Connect to the websocket.\n with client.ml.ml_copilot_ws(replay=None,\n conversation_id=None,\n pr=None) as websocket:\n\n # Send a message.\n websocket.send(MlCopilotClientMessage(OptionProjectContext(\ncurrent_files={\"<string>\": b\"<bytes>\"},\n)))\n\n # Get a message.\n message = websocket.recv()\n print(message)\n\n ",
"libDocsLink": "https://python.api.docs.zoo.dev/_autosummary/kittycad.KittyCAD.html#kittycad.KittyCAD.ml"
}
},
{
"op": "add",
"path": "/paths/~1ws~1ml~1reasoning~1{id}/get/x-python",
"value": {
"example": "from kittycad.models import MlCopilotClientMessage\nfrom kittycad.models.ml_copilot_client_message import OptionProjectContext\nfrom kittycad.models import MlCopilotServerMessage\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_ml_reasoning_ws():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n # Connect to the websocket.\n with client.ml.ml_reasoning_ws(id=\"<string>\") as websocket:\n\n # Send a message.\n websocket.send(MlCopilotClientMessage(OptionProjectContext(\ncurrent_files={\"<string>\": b\"<bytes>\"},\n)))\n\n # Get a message.\n message = websocket.recv()\n print(message)\n\n ",
"example": "from kittycad.models import MlCopilotClientMessage\nfrom kittycad.models.ml_copilot_client_message import OptionListModes\nfrom kittycad.models import MlCopilotServerMessage\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_ml_reasoning_ws():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n # Connect to the websocket.\n with client.ml.ml_reasoning_ws(id=\"<string>\") as websocket:\n\n # Send a message.\n websocket.send(MlCopilotClientMessage(OptionListModes()))\n\n # Get a message.\n message = websocket.recv()\n print(message)\n\n ",
"libDocsLink": "https://python.api.docs.zoo.dev/_autosummary/kittycad.KittyCAD.html#kittycad.KittyCAD.ml"
}
},
{
"op": "add",
"path": "/paths/~1ws~1modeling~1commands/get/x-python",
"value": {
"example": "from kittycad.models.post_effect_type import PostEffectType\nfrom kittycad.models import WebSocketRequest\nfrom kittycad.models.web_socket_request import OptionTrickleIce\nfrom kittycad.models.rtc_ice_candidate_init import RtcIceCandidateInit\nfrom kittycad.models import WebSocketResponse\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_modeling_commands_ws():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n # Connect to the websocket.\n with client.modeling.modeling_commands_ws(video_res_width=10,\n video_res_height=10,\n fps=10,\n unlocked_framerate=False,\n post_effect=PostEffectType.PHOSPHOR,\n webrtc=False,\n show_grid=False,\n order_independent_transparency=False,\n pool=None,\n replay=None,\n api_call_id=None,\n pr=None) as websocket:\n\n # Send a message.\n websocket.send(WebSocketRequest(OptionTrickleIce(\ncandidate=RtcIceCandidateInit(\ncandidate=\"<string>\",\n),\n)))\n\n # Get a message.\n message = websocket.recv()\n print(message)\n\n ",
"example": "from kittycad.models.post_effect_type import PostEffectType\nfrom kittycad.models import WebSocketRequest\nfrom kittycad.models.web_socket_request import OptionDebug\nfrom kittycad.models import WebSocketResponse\nfrom typing import Union, Any, Optional, List, Tuple\nfrom kittycad.types import Response\ndef example_modeling_commands_ws():\n client = KittyCAD() # Uses KITTYCAD_API_TOKEN environment variable\n\n # Connect to the websocket.\n with client.modeling.modeling_commands_ws(video_res_width=10,\n video_res_height=10,\n fps=10,\n unlocked_framerate=False,\n post_effect=PostEffectType.PHOSPHOR,\n webrtc=False,\n show_grid=False,\n order_independent_transparency=False,\n pool=None,\n replay=None,\n api_call_id=None,\n pr=None) as websocket:\n\n # Send a message.\n websocket.send(WebSocketRequest(OptionDebug()))\n\n # Get a message.\n message = websocket.recv()\n print(message)\n\n ",
"libDocsLink": "https://python.api.docs.zoo.dev/_autosummary/kittycad.KittyCAD.html#kittycad.KittyCAD.modeling"
}
}
Expand Down
3 changes: 3 additions & 0 deletions kittycad/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,4 +572,7 @@
from .zookeeper_auto_router_metadata import ZookeeperAutoRouterMetadata
from .zookeeper_edit_patch import ZookeeperEditPatch
from .zookeeper_edit_patch_file import ZookeeperEditPatchFile
from .zookeeper_turn_usage import ZookeeperTurnUsage
from .zookeeper_turn_usage_model import ZookeeperTurnUsageModel
from .zookeeper_turn_usage_stage import ZookeeperTurnUsageStage
from .zoom_to_fit import ZoomToFit
4 changes: 4 additions & 0 deletions kittycad/models/ml_copilot_client_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ class OptionUser(KittyCadBaseModel):

content: str

correlation_id: Optional[Uuid] = None

current_files: Optional[Dict[str, bytes]] = None

engine_api_call_id: Optional[Uuid] = None

forced_tools: Optional[List[MlCopilotTool]] = None

mode: Optional[MlCopilotMode] = None
Expand Down
12 changes: 11 additions & 1 deletion kittycad/models/ml_copilot_server_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from ..models.zookeeper_auto_router_metadata import (
ZookeeperAutoRouterMetadata as ZookeeperAutoRouterMetadataModel,
)
from ..models.zookeeper_turn_usage import ZookeeperTurnUsage as ZookeeperTurnUsageModel
from .base import KittyCadBaseModel


Expand Down Expand Up @@ -310,6 +311,14 @@ class ZookeeperAutoRouterMetadata(KittyCadBaseModel):
zookeeper_auto_router_metadata: ZookeeperAutoRouterMetadataModel


class ZookeeperTurnUsage(KittyCadBaseModel):
"""Backend-only token usage and cost for one completed Zookeeper turn.

Sent just before `EndOfStream`. API records it in `meta.usage` on the turn's `EndOfStream` message row, alongside the `meta.billing` revenue figures, and never forwards it to clients or replays it as a chat message. It exists so spend can be compared against what the turn was billed; it is not customer-facing."""

zookeeper_turn_usage: ZookeeperTurnUsageModel


class ZookeeperRecoveryToolOutput(KittyCadBaseModel):
"""Backend-only completed tool result used for portable Zookeeper recovery.

Expand Down Expand Up @@ -345,7 +354,7 @@ def _wrap(self, handler, info):
class Replay(KittyCadBaseModel):
"""Replay containing raw bytes for previously-saved messages for a conversation. Includes server messages and client `User` messages.

Invariants: - Client replay includes server messages: `Info`, `Error`, `Reasoning(..)`, `ToolOutput { .. }`, `Files { .. }`, `ProjectUpdated { .. }`, and `EndOfStream { .. }`. - Client replay also includes client `User` messages. - Backend replay includes client `User` messages plus selected reasoning, edit metadata, recovery output, and final responses. - The following are NEVER included: `SessionData`, `ConversationId`, `Delta`, `BackendShutdown`, or `ZookeeperAutoRouterMetadata`. - `ZookeeperRecoveryToolOutput` is included only in replay sent to the text-to-CAD backend and is filtered from client replay. - Ordering is stable: messages are ordered by prompt creation time within the conversation, then by the per-prompt `seq` value (monotonically increasing as seen in the original stream).
Invariants: - Client replay includes server messages: `Info`, `Error`, `Reasoning(..)`, `ToolOutput { .. }`, `Files { .. }`, `ProjectUpdated { .. }`, and `EndOfStream { .. }`. - Client replay also includes client `User` messages. - Backend replay includes client `User` messages plus selected reasoning, edit metadata, recovery output, and final responses. - The following are NEVER included: `SessionData`, `ConversationId`, `Delta`, `BackendShutdown`, `ZookeeperAutoRouterMetadata`, or `ZookeeperTurnUsage`. - `ZookeeperRecoveryToolOutput` is included only in replay sent to the text-to-CAD backend and is filtered from client replay. - Ordering is stable: messages are ordered by prompt creation time within the conversation, then by the per-prompt `seq` value (monotonically increasing as seen in the original stream).

Wire format: - Each element is canonical serialized bytes (typically JSON) for either a `MlCopilotServerMessage` or a `MlCopilotClientMessage::User`. - When delivered as an initial replay over the websocket (upon `?replay=true&conversation_id=<uuid>`), the server sends a single WebSocket Binary frame containing a MsgPack-encoded document of this enum: `Replay { messages }`."""

Expand Down Expand Up @@ -442,6 +451,7 @@ def _wrap(self, handler, info):
RequestAttachments,
AttachmentsLoaded,
ZookeeperAutoRouterMetadata,
ZookeeperTurnUsage,
ZookeeperRecoveryToolOutput,
Replay,
EndOfStream,
Expand Down
47 changes: 47 additions & 0 deletions kittycad/models/zookeeper_turn_usage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from typing import List, Optional

from ..models.zookeeper_turn_usage_model import ZookeeperTurnUsageModel
from ..models.zookeeper_turn_usage_stage import ZookeeperTurnUsageStage
from .base import KittyCadBaseModel


class ZookeeperTurnUsage(KittyCadBaseModel):
"""Token usage and cost for one completed Zookeeper turn.

A turn is many model calls: the streamed agent loop, helper agents, conversation compaction, Auto-mode routing, and any retried attempts. This is the sum of all of them, with breakdowns by model and by stage."""

api_call_id: Optional[str] = None

cache_write_input_tokens: Optional[int] = 0

cached_input_tokens: Optional[int] = 0

conversation_id: Optional[str] = None

cost_micro_usd: Optional[int] = 0

cost_usd: Optional[str] = ""

fully_priced: Optional[bool] = False

input_tokens: Optional[int] = 0

models: Optional[List[ZookeeperTurnUsageModel]] = None

output_tokens: Optional[int] = 0

priced_requests: Optional[int] = 0

reasoning_tokens: Optional[int] = 0

requests: Optional[int] = 0

schema_version: Optional[str] = ""

stages: Optional[List[ZookeeperTurnUsageStage]] = None

total_tokens: Optional[int] = 0

uncached_input_tokens: Optional[int] = 0

unpriced_requests: Optional[int] = 0
37 changes: 37 additions & 0 deletions kittycad/models/zookeeper_turn_usage_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from typing import Optional

from .base import KittyCadBaseModel


class ZookeeperTurnUsageModel(KittyCadBaseModel):
"""Per-model usage within a Zookeeper turn."""

cache_write_input_tokens: Optional[int] = 0

cached_input_tokens: Optional[int] = 0

cost_micro_usd: Optional[int] = 0

cost_usd: Optional[str] = ""

fully_priced: Optional[bool] = False

input_tokens: Optional[int] = 0

model: str

output_tokens: Optional[int] = 0

priced_requests: Optional[int] = 0

pricing_source: Optional[str] = ""

reasoning_tokens: Optional[int] = 0

requests: Optional[int] = 0

total_tokens: Optional[int] = 0

uncached_input_tokens: Optional[int] = 0

unpriced_requests: Optional[int] = 0
35 changes: 35 additions & 0 deletions kittycad/models/zookeeper_turn_usage_stage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import Optional

from .base import KittyCadBaseModel


class ZookeeperTurnUsageStage(KittyCadBaseModel):
"""Per-stage usage within a Zookeeper turn."""

cache_write_input_tokens: Optional[int] = 0

cached_input_tokens: Optional[int] = 0

cost_micro_usd: Optional[int] = 0

cost_usd: Optional[str] = ""

fully_priced: Optional[bool] = False

input_tokens: Optional[int] = 0

output_tokens: Optional[int] = 0

priced_requests: Optional[int] = 0

reasoning_tokens: Optional[int] = 0

requests: Optional[int] = 0

stage: str

total_tokens: Optional[int] = 0

uncached_input_tokens: Optional[int] = 0

unpriced_requests: Optional[int] = 0
Loading
Loading