forked from 1b-agent/opencadstudio-upstream
Merge branch 'main' into feature/parametric-constraint-system
# Conflicts: # src/app/automation.rs # src/app/mod.rs # src/ui/ribbon/widgets.rs
This commit is contained in:
commit
e2d39b049d
114 files changed
+13641
-1685
No files matched your search
@@ -13,15 +13,15 @@ The client must start that command over standard input/output. If it asks for th
|
||||
The server provides four tools:
|
||||
|
||||
- `ocs_sessions` finds running editor sessions and opens OpenCADStudio when none exists.
|
||||
- `ocs_read` reads document state, command manifests, entities, layers, properties, kernel measurements and spatial relationships, history, events, and operation status.
|
||||
- `ocs_execute` performs one operation or a sequential batch against the real editor.
|
||||
- `ocs_read` discovers capabilities and reads document state, complete database records, command manifests, entities, properties, kernel measurements and spatial relationships, history, events, and operation status.
|
||||
- `ocs_execute` performs one operation, an atomic record update, or a sequential batch against the real editor.
|
||||
- `ocs_capture` returns a bounded PNG of the drawing viewport or complete window.
|
||||
|
||||
The normal flow is to call `ocs_sessions`, read the chosen session with `ocs_read`, then pass the returned document state into `ocs_execute`. For example, an undo request has this shape:
|
||||
The normal flow is to call `ocs_sessions`, pass its returned `session_id` as `ocs_session_id` to the other tools, read the chosen session with `ocs_read`, then pass the returned document state into `ocs_execute`. For example, an undo request has this shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"ocs_session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"request": {
|
||||
"op": "undo",
|
||||
"request_id": "undo-1",
|
||||
@@ -31,13 +31,72 @@ The normal flow is to call `ocs_sessions`, read the chosen session with `ocs_rea
|
||||
}
|
||||
```
|
||||
|
||||
Call `ocs_read` with `op: "capabilities"` before unfamiliar work. It reports the command, geometry, transaction, capture, and database facilities supported by the running build. The `records.collections` list gives every available database collection, its record count, and whether it can be edited.
|
||||
|
||||
Call `ocs_read` with `op: "record_schema"` before editing an unfamiliar record. With no parameters it lists the complete generated type registry. A collection returns the record types accepted by that collection even when the current drawing has no instance of a type. Supplying both `collection` and `type` returns the type's complete dependency graph, flattened property paths, JSON types, optional and sequence markers, enum variants, integer bounds, unambiguous unit annotations, identity fields, and write rules:
|
||||
|
||||
```json
|
||||
{
|
||||
"ocs_session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"op": "record_schema",
|
||||
"parameters": {
|
||||
"collection": "entities",
|
||||
"type": "Insert"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Sequence fields include an `item_path_template` such as `/attributes/{index}`. Replace `{index}` with an index returned by `records` before using the path in `set_properties`. When a matching record exists, `runtime_schema` adds its exact JSON shape and bounded scalar examples. The embedded registry is generated from all 48 entity variants, all 36 non-graphical object variants, symbol-table records, header data, summary data, and the remaining stored record roots at build time.
|
||||
|
||||
`op: "records"` returns every serializable property of entities, non-graphical objects, symbol-table records, the complete header, document metadata, and derived database views. Omitting `collection` returns the same collection manifest; use `collection: "all"` for a paged query across the complete database. Records have a stable collection plus a handle or name, a type, and `properties`. Entity records also include their display and file record type names.
|
||||
|
||||
Property filters and projections use RFC 6901 JSON Pointer paths relative to `properties`. Multiple `where` filters are combined with AND. Supported operators are `eq`, `ne`, `lt`, `lte`, `gt`, `gte`, `contains`, `starts_with`, `ends_with`, `in`, `exists`, and `not_exists`:
|
||||
|
||||
```json
|
||||
{
|
||||
"ocs_session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"op": "records",
|
||||
"parameters": {
|
||||
"collection": "entities",
|
||||
"type": "Insert",
|
||||
"where": [
|
||||
{"path": "/common/layer", "value": "Equipment"},
|
||||
{"path": "/attributes/0/tag", "value": "COMPANY"}
|
||||
],
|
||||
"paths": ["/block_name", "/insert_point", "/attributes"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `set_properties` to replace one or more fields atomically. OCS verifies the record identity, JSON types, optional compare-and-set values, layer locks, document revision, and request ID before committing one undoable edit. Handles, ownership slots, table names, and other database identity fields are read-only; their dedicated editor commands preserve cross-record references.
|
||||
|
||||
```json
|
||||
{
|
||||
"ocs_session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"request": {
|
||||
"op": "set_properties",
|
||||
"request_id": "attributes-1",
|
||||
"document_id": 1,
|
||||
"revision": 12,
|
||||
"collection": "entities",
|
||||
"handle": "2A",
|
||||
"updates": [
|
||||
{"path": "/attributes/0/value", "expected": "BPH", "value": "Updated"},
|
||||
{"path": "/insert_point/z", "value": 3.0}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The same operation edits entries in `objects`, every symbol table, `header`, and `summary_info`. Collections marked `mutable: false` are derived or storage metadata and remain queryable. Their source records must be changed so OCS can rebuild those views consistently.
|
||||
|
||||
To discover command syntax without reading application source, call `ocs_read` with `op: "commands"`. The unfiltered response lists commands and actions. Add `parameters: {"name": "PLINE"}` for a command's batch examples and interactive guidance.
|
||||
|
||||
A complete command can be sent with `run`. Prompt answers are separated by spaces, points use `x,y` or `x,y,z`, and option answers use their displayed token:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"ocs_session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"request": {
|
||||
"op": "run",
|
||||
"request_id": "polyline-1",
|
||||
@@ -52,7 +111,7 @@ Use `batch` when the steps are already known. OCS supplies each step with the st
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"ocs_session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"response_detail": "changed_entities",
|
||||
"request": {
|
||||
"op": "batch",
|
||||
@@ -67,11 +126,11 @@ Use `batch` when the steps are already known. OCS supplies each step with the st
|
||||
|
||||
Execute responses use `response_detail: "compact"` by default and return only the state needed for the next edit. Use `changed_entities` to receive the current geometry of affected handles in the same response, or `full` when the complete editor state is needed.
|
||||
|
||||
`ocs_read` query accepts exact handles, type/layer filters, field projection, world-XY bounds, nearest-curve ranking, closed-curve containment, and exact intersections between two planar curves. Nearest points, containment, curve length, area, and intersections are calculated by the geometry kernel:
|
||||
`ocs_read` query accepts exact handles, type/layer filters, field projection, world-XY bounds, nearest-curve ranking, closed-curve containment, and exact intersections between two planar curves. `detail: "full"` adds the complete serialized entity properties. Nearest points, containment, curve length, area, and intersections are calculated by the geometry kernel:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"ocs_session_id": "SESSION_FROM_OCS_SESSIONS",
|
||||
"op": "query",
|
||||
"parameters": {"intersections": ["2A", "31"]}
|
||||
}
|
||||
|
||||
@@ -98,14 +98,14 @@ def main() -> None:
|
||||
if active.get("start"):
|
||||
client.tool(
|
||||
"ocs_execute",
|
||||
{"session_id": session, "request": {"op": "new", "request_id": "eval-new"}},
|
||||
{"ocs_session_id": session, "request": {"op": "new", "request_id": "eval-new"}},
|
||||
)
|
||||
|
||||
base = 1_000_000 + int(time.time()) % 100_000
|
||||
draw = client.tool(
|
||||
"ocs_execute",
|
||||
{
|
||||
"session_id": session,
|
||||
"ocs_session_id": session,
|
||||
"response_detail": "changed_entities",
|
||||
"wait_seconds": 0,
|
||||
"request": {
|
||||
@@ -129,19 +129,19 @@ def main() -> None:
|
||||
|
||||
crossings = client.tool(
|
||||
"ocs_read",
|
||||
{"session_id": session, "op": "query", "parameters": {"intersections": line_handles}},
|
||||
{"ocs_session_id": session, "op": "query", "parameters": {"intersections": line_handles}},
|
||||
)
|
||||
assert crossings["count"] == 1 and crossings["intersections"][0]["point"] == [base, 0.0]
|
||||
|
||||
nearest = client.tool(
|
||||
"ocs_read",
|
||||
{"session_id": session, "op": "query", "parameters": {"near": [base + 20, 0], "handles": handles, "limit": 1}},
|
||||
{"ocs_session_id": session, "op": "query", "parameters": {"near": [base + 20, 0], "handles": handles, "limit": 1}},
|
||||
)
|
||||
assert nearest["entities"][0]["handle"] == circle_handles[0]
|
||||
|
||||
measured = client.tool(
|
||||
"ocs_read",
|
||||
{"session_id": session, "op": "measure", "parameters": {"handles": circle_handles}},
|
||||
{"ocs_session_id": session, "op": "measure", "parameters": {"handles": circle_handles}},
|
||||
)
|
||||
assert abs(measured["measurements"][0]["curve"]["area"] - 12.566370614359172) < 1e-9
|
||||
succeeded = True
|
||||
@@ -151,7 +151,7 @@ def main() -> None:
|
||||
client.tool(
|
||||
"ocs_execute",
|
||||
{
|
||||
"session_id": session,
|
||||
"ocs_session_id": session,
|
||||
"request": {
|
||||
"op": "batch",
|
||||
"request_id": f"eval-clean-{base}",
|
||||
|
||||
@@ -52,9 +52,13 @@ def legacy(server: Path) -> None:
|
||||
names = set(definitions)
|
||||
assert names == TOOLS, names
|
||||
execute_request = definitions["ocs_execute"]["inputSchema"]["properties"]["request"]
|
||||
assert len(execute_request["oneOf"]) == 15
|
||||
assert len(execute_request["oneOf"]) == 16
|
||||
assert execute_request["properties"]["steps"]["maxItems"] == 64
|
||||
assert execute_request["properties"]["cmd"]["examples"][0] == "LINE 0,0 10,10"
|
||||
assert "set_properties" in execute_request["properties"]["op"]["enum"]
|
||||
assert "record_schema" in definitions["ocs_read"]["inputSchema"]["properties"]["op"]["enum"]
|
||||
read_parameters = definitions["ocs_read"]["inputSchema"]["properties"]["parameters"]["properties"]
|
||||
assert {"collection", "where", "paths"} <= set(read_parameters)
|
||||
assert execute_request["properties"]["kind"]["enum"] == [
|
||||
"text", "token", "point", "entity", "structure", "selection", "enter"
|
||||
]
|
||||
@@ -110,7 +114,7 @@ def modern(server: Path) -> None:
|
||||
"params": {
|
||||
"name": "ocs_execute",
|
||||
"arguments": {
|
||||
"session_id": "missing",
|
||||
"ocs_session_id": "missing",
|
||||
"request": {"op": "run", "request_id": "run-1"},
|
||||
},
|
||||
"_meta": meta,
|
||||
@@ -126,7 +130,7 @@ def modern(server: Path) -> None:
|
||||
"method": "tools/call",
|
||||
"params": {
|
||||
"name": "ocs_execute",
|
||||
"arguments": {"session_id": "missing", "request": {"op": "undo"}},
|
||||
"arguments": {"ocs_session_id": "missing", "request": {"op": "undo"}},
|
||||
"_meta": meta,
|
||||
},
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user