@cuylabs/agent-physical 5.0.2

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,225 @@
1
+ import { Tool } from '@cuylabs/agent-core/tool';
2
+ import { z } from 'zod';
3
+ import { RiskLevel } from '@cuylabs/agent-core/safety';
4
+
5
+ type PhysicalSessionStatus = "idle" | "starting" | "ready" | "running" | "awaiting-input" | "complete" | "stopping" | "stopped" | "error";
6
+ type PhysicalExecutionMode = "simulation" | "hardware" | "hybrid" | "unknown";
7
+ type PhysicalObservationKind = "rgb" | "depth" | "point-cloud" | "joint-state" | "pose" | "text" | "video" | "artifact";
8
+ type PhysicalFrame = "world" | "robot-base" | "camera" | "tool" | string;
9
+ interface PhysicalVector3 {
10
+ x: number;
11
+ y: number;
12
+ z: number;
13
+ }
14
+ interface PhysicalQuaternionWxyz {
15
+ w: number;
16
+ x: number;
17
+ y: number;
18
+ z: number;
19
+ }
20
+ interface PhysicalPose {
21
+ position: PhysicalVector3;
22
+ orientation?: PhysicalQuaternionWxyz;
23
+ frame?: PhysicalFrame;
24
+ }
25
+ interface PhysicalImageObservation {
26
+ kind: "rgb" | "depth";
27
+ source: string;
28
+ width?: number;
29
+ height?: number;
30
+ mimeType?: string;
31
+ dataUrl?: string;
32
+ uri?: string;
33
+ frame?: PhysicalFrame;
34
+ timestamp?: number;
35
+ }
36
+ interface PhysicalTextObservation {
37
+ kind: "text";
38
+ source: string;
39
+ text: string;
40
+ timestamp?: number;
41
+ }
42
+ interface PhysicalStructuredObservation {
43
+ kind: Exclude<PhysicalObservationKind, "rgb" | "depth" | "text">;
44
+ source: string;
45
+ data: unknown;
46
+ frame?: PhysicalFrame;
47
+ timestamp?: number;
48
+ }
49
+ type PhysicalObservationItem = PhysicalImageObservation | PhysicalTextObservation | PhysicalStructuredObservation;
50
+ interface PhysicalObservation {
51
+ sessionId: string;
52
+ status?: PhysicalSessionStatus;
53
+ taskId?: string;
54
+ summary?: string;
55
+ items: PhysicalObservationItem[];
56
+ metadata?: Record<string, unknown>;
57
+ timestamp: number;
58
+ }
59
+ interface PhysicalTaskSpec {
60
+ id: string;
61
+ description: string;
62
+ goal?: string;
63
+ environment?: string;
64
+ mode?: PhysicalExecutionMode;
65
+ metadata?: Record<string, unknown>;
66
+ }
67
+ interface PhysicalSafetyPolicy {
68
+ riskLevel?: RiskLevel;
69
+ requiresApproval?: boolean;
70
+ requiresHumanPresence?: boolean;
71
+ allowedModes?: PhysicalExecutionMode[];
72
+ emergencyStopRequired?: boolean;
73
+ notes?: string[];
74
+ }
75
+ interface PhysicalCapability {
76
+ name: string;
77
+ description: string;
78
+ safety?: PhysicalSafetyPolicy;
79
+ inputSchema?: unknown;
80
+ outputSchema?: unknown;
81
+ metadata?: Record<string, unknown>;
82
+ }
83
+ interface PhysicalExecutionRequest {
84
+ code: string;
85
+ language?: "python" | "typescript" | "javascript" | string;
86
+ timeoutMs?: number;
87
+ dryRun?: boolean;
88
+ metadata?: Record<string, unknown>;
89
+ }
90
+ interface PhysicalOutcome {
91
+ success: boolean;
92
+ reward?: number;
93
+ taskCompleted?: boolean;
94
+ terminated?: boolean;
95
+ truncated?: boolean;
96
+ reason?: string;
97
+ metadata?: Record<string, unknown>;
98
+ }
99
+ interface PhysicalArtifact {
100
+ id: string;
101
+ kind: "code" | "log" | "image" | "video" | "json" | "directory" | "other";
102
+ uri: string;
103
+ label?: string;
104
+ mimeType?: string;
105
+ metadata?: Record<string, unknown>;
106
+ }
107
+ interface PhysicalExecutionTrace {
108
+ id: string;
109
+ startedAt: number;
110
+ completedAt?: number;
111
+ request?: PhysicalExecutionRequest;
112
+ stdout?: string;
113
+ stderr?: string;
114
+ observations?: PhysicalObservation[];
115
+ artifacts?: PhysicalArtifact[];
116
+ outcome?: PhysicalOutcome;
117
+ metadata?: Record<string, unknown>;
118
+ }
119
+ interface PhysicalSessionState {
120
+ sessionId: string;
121
+ status: PhysicalSessionStatus;
122
+ task?: PhysicalTaskSpec;
123
+ mode?: PhysicalExecutionMode;
124
+ startedAt?: number;
125
+ updatedAt: number;
126
+ message?: string;
127
+ metadata?: Record<string, unknown>;
128
+ }
129
+ interface PhysicalSessionStartOptions {
130
+ task?: PhysicalTaskSpec;
131
+ metadata?: Record<string, unknown>;
132
+ }
133
+ interface PhysicalObserveOptions {
134
+ includeImages?: boolean;
135
+ includeArtifacts?: boolean;
136
+ maxItems?: number;
137
+ }
138
+ interface PhysicalListArtifactsOptions {
139
+ kind?: PhysicalArtifact["kind"];
140
+ limit?: number;
141
+ }
142
+ interface PhysicalSession {
143
+ readonly id: string;
144
+ readonly capabilities?: readonly PhysicalCapability[];
145
+ getState(): Promise<PhysicalSessionState> | PhysicalSessionState;
146
+ start?(options?: PhysicalSessionStartOptions): Promise<PhysicalSessionState>;
147
+ reset?(options?: PhysicalSessionStartOptions): Promise<PhysicalSessionState>;
148
+ observe?(options?: PhysicalObserveOptions): Promise<PhysicalObservation>;
149
+ executeCode?(request: PhysicalExecutionRequest): Promise<PhysicalExecutionTrace>;
150
+ listArtifacts?(options?: PhysicalListArtifactsOptions): Promise<PhysicalArtifact[]>;
151
+ stop(reason?: string): Promise<PhysicalSessionState>;
152
+ }
153
+ interface PhysicalAdapter<TOptions = unknown> {
154
+ readonly name: string;
155
+ createSession(options: TOptions): Promise<PhysicalSession> | PhysicalSession;
156
+ }
157
+ interface PhysicalToolMetadata {
158
+ physical?: {
159
+ sessionId: string;
160
+ status?: PhysicalSessionStatus;
161
+ observation?: PhysicalObservation;
162
+ trace?: PhysicalExecutionTrace;
163
+ artifacts?: PhysicalArtifact[];
164
+ state?: PhysicalSessionState;
165
+ };
166
+ [key: string]: unknown;
167
+ }
168
+ type PhysicalTool = Tool.Info;
169
+
170
+ interface PhysicalToolOptions {
171
+ /**
172
+ * Prefix used for generated tool ids. Defaults to "physical".
173
+ */
174
+ prefix?: string;
175
+ }
176
+ declare function createPhysicalStatusTool(session: PhysicalSession, options?: PhysicalToolOptions): Tool.Info<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, PhysicalToolMetadata>;
177
+ declare function createPhysicalObserveTool(session: PhysicalSession, options?: PhysicalToolOptions): Tool.Info<z.ZodObject<{
178
+ includeImages: z.ZodOptional<z.ZodBoolean>;
179
+ includeArtifacts: z.ZodOptional<z.ZodBoolean>;
180
+ maxItems: z.ZodOptional<z.ZodNumber>;
181
+ }, "strip", z.ZodTypeAny, {
182
+ includeImages?: boolean | undefined;
183
+ includeArtifacts?: boolean | undefined;
184
+ maxItems?: number | undefined;
185
+ }, {
186
+ includeImages?: boolean | undefined;
187
+ includeArtifacts?: boolean | undefined;
188
+ maxItems?: number | undefined;
189
+ }>, PhysicalToolMetadata>;
190
+ declare function createPhysicalRunCodeTool(session: PhysicalSession, options?: PhysicalToolOptions): Tool.Info<z.ZodObject<{
191
+ code: z.ZodString;
192
+ language: z.ZodOptional<z.ZodString>;
193
+ timeoutMs: z.ZodOptional<z.ZodNumber>;
194
+ dryRun: z.ZodOptional<z.ZodBoolean>;
195
+ }, "strip", z.ZodTypeAny, {
196
+ code: string;
197
+ language?: string | undefined;
198
+ timeoutMs?: number | undefined;
199
+ dryRun?: boolean | undefined;
200
+ }, {
201
+ code: string;
202
+ language?: string | undefined;
203
+ timeoutMs?: number | undefined;
204
+ dryRun?: boolean | undefined;
205
+ }>, PhysicalToolMetadata>;
206
+ declare function createPhysicalStopTool(session: PhysicalSession, options?: PhysicalToolOptions): Tool.Info<z.ZodObject<{
207
+ reason: z.ZodOptional<z.ZodString>;
208
+ }, "strip", z.ZodTypeAny, {
209
+ reason?: string | undefined;
210
+ }, {
211
+ reason?: string | undefined;
212
+ }>, PhysicalToolMetadata>;
213
+ declare function createPhysicalArtifactsTool(session: PhysicalSession, options?: PhysicalToolOptions): Tool.Info<z.ZodObject<{
214
+ kind: z.ZodOptional<z.ZodEnum<["code", "log", "image", "video", "json", "directory", "other"]>>;
215
+ limit: z.ZodOptional<z.ZodNumber>;
216
+ }, "strip", z.ZodTypeAny, {
217
+ kind?: "video" | "code" | "log" | "image" | "json" | "directory" | "other" | undefined;
218
+ limit?: number | undefined;
219
+ }, {
220
+ kind?: "video" | "code" | "log" | "image" | "json" | "directory" | "other" | undefined;
221
+ limit?: number | undefined;
222
+ }>, PhysicalToolMetadata>;
223
+ declare function createPhysicalSessionTools(session: PhysicalSession, options?: PhysicalToolOptions): Tool.AnyInfo[];
224
+
225
+ export { type PhysicalVector3 as A, createPhysicalArtifactsTool as B, createPhysicalObserveTool as C, createPhysicalRunCodeTool as D, createPhysicalSessionTools as E, createPhysicalStatusTool as F, createPhysicalStopTool as G, type PhysicalSafetyPolicy as P, type PhysicalSessionState as a, type PhysicalExecutionMode as b, type PhysicalAdapter as c, type PhysicalArtifact as d, type PhysicalCapability as e, type PhysicalExecutionRequest as f, type PhysicalExecutionTrace as g, type PhysicalFrame as h, type PhysicalImageObservation as i, type PhysicalListArtifactsOptions as j, type PhysicalObservation as k, type PhysicalObservationItem as l, type PhysicalObservationKind as m, type PhysicalObserveOptions as n, type PhysicalOutcome as o, type PhysicalPose as p, type PhysicalQuaternionWxyz as q, type PhysicalSession as r, type PhysicalSessionStartOptions as s, type PhysicalSessionStatus as t, type PhysicalStructuredObservation as u, type PhysicalTaskSpec as v, type PhysicalTextObservation as w, type PhysicalTool as x, type PhysicalToolMetadata as y, type PhysicalToolOptions as z };
@@ -0,0 +1,12 @@
1
+ import { P as PhysicalSafetyPolicy, a as PhysicalSessionState, b as PhysicalExecutionMode } from './index-pM6qWmMq.js';
2
+ export { c as PhysicalAdapter, d as PhysicalArtifact, e as PhysicalCapability, f as PhysicalExecutionRequest, g as PhysicalExecutionTrace, h as PhysicalFrame, i as PhysicalImageObservation, j as PhysicalListArtifactsOptions, k as PhysicalObservation, l as PhysicalObservationItem, m as PhysicalObservationKind, n as PhysicalObserveOptions, o as PhysicalOutcome, p as PhysicalPose, q as PhysicalQuaternionWxyz, r as PhysicalSession, s as PhysicalSessionStartOptions, t as PhysicalSessionStatus, u as PhysicalStructuredObservation, v as PhysicalTaskSpec, w as PhysicalTextObservation, x as PhysicalTool, y as PhysicalToolMetadata, z as PhysicalToolOptions, A as PhysicalVector3, B as createPhysicalArtifactsTool, C as createPhysicalObserveTool, D as createPhysicalRunCodeTool, E as createPhysicalSessionTools, F as createPhysicalStatusTool, G as createPhysicalStopTool } from './index-pM6qWmMq.js';
3
+ import '@cuylabs/agent-core/tool';
4
+ import 'zod';
5
+ import '@cuylabs/agent-core/safety';
6
+
7
+ declare const defaultPhysicalSafetyPolicy: Required<Pick<PhysicalSafetyPolicy, "riskLevel" | "requiresApproval" | "requiresHumanPresence">>;
8
+ declare function normalizePhysicalSafetyPolicy(policy: PhysicalSafetyPolicy | undefined): PhysicalSafetyPolicy;
9
+ declare function isModeAllowed(mode: PhysicalExecutionMode | undefined, policy: PhysicalSafetyPolicy | undefined): boolean;
10
+ declare function describePhysicalState(state: PhysicalSessionState): string;
11
+
12
+ export { PhysicalExecutionMode, PhysicalSafetyPolicy, PhysicalSessionState, defaultPhysicalSafetyPolicy, describePhysicalState, isModeAllowed, normalizePhysicalSafetyPolicy };
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ import {
2
+ createPhysicalArtifactsTool,
3
+ createPhysicalObserveTool,
4
+ createPhysicalRunCodeTool,
5
+ createPhysicalSessionTools,
6
+ createPhysicalStatusTool,
7
+ createPhysicalStopTool,
8
+ defaultPhysicalSafetyPolicy,
9
+ describePhysicalState,
10
+ isModeAllowed,
11
+ normalizePhysicalSafetyPolicy
12
+ } from "./chunk-G7CGE7QH.js";
13
+ export {
14
+ createPhysicalArtifactsTool,
15
+ createPhysicalObserveTool,
16
+ createPhysicalRunCodeTool,
17
+ createPhysicalSessionTools,
18
+ createPhysicalStatusTool,
19
+ createPhysicalStopTool,
20
+ defaultPhysicalSafetyPolicy,
21
+ describePhysicalState,
22
+ isModeAllowed,
23
+ normalizePhysicalSafetyPolicy
24
+ };
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,4 @@
1
+ import '@cuylabs/agent-core/tool';
2
+ import 'zod';
3
+ export { z as PhysicalToolOptions, B as createPhysicalArtifactsTool, C as createPhysicalObserveTool, D as createPhysicalRunCodeTool, E as createPhysicalSessionTools, F as createPhysicalStatusTool, G as createPhysicalStopTool } from '../index-pM6qWmMq.js';
4
+ import '@cuylabs/agent-core/safety';
@@ -0,0 +1,17 @@
1
+ import {
2
+ createPhysicalArtifactsTool,
3
+ createPhysicalObserveTool,
4
+ createPhysicalRunCodeTool,
5
+ createPhysicalSessionTools,
6
+ createPhysicalStatusTool,
7
+ createPhysicalStopTool
8
+ } from "../chunk-G7CGE7QH.js";
9
+ export {
10
+ createPhysicalArtifactsTool,
11
+ createPhysicalObserveTool,
12
+ createPhysicalRunCodeTool,
13
+ createPhysicalSessionTools,
14
+ createPhysicalStatusTool,
15
+ createPhysicalStopTool
16
+ };
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/docs/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # @cuylabs/agent-physical Docs
2
+
3
+ Start here:
4
+
5
+ - [Architecture](./architecture.md) explains the package boundary and why
6
+ robotics-specific semantics live outside `agent-core`.
7
+ - [Safety](./safety.md) describes how physical capabilities should interact
8
+ with approvals, replay, and stop controls.
9
+
10
+ ## Core Concepts
11
+
12
+ `PhysicalSession` is the central contract. A session represents one simulator,
13
+ robot, or embodied runtime episode. It can expose status, observation, artifacts,
14
+ optional reset/start operations, optional code execution, and stop control.
15
+
16
+ `PhysicalObservation` is a timestamped set of observation items. Items can be
17
+ images, depth, point clouds, joint state, poses, text summaries, video
18
+ references, or artifacts.
19
+
20
+ `PhysicalCapability` is descriptive metadata for what a backend can do. It
21
+ exists separately from `agent-core` tools because physical capabilities need
22
+ safety policy, world-state assumptions, and backend metadata.
23
+
24
+ `PhysicalExecutionTrace` captures what happened after a policy or command was
25
+ executed: stdout, stderr, observations, artifacts, and outcome.
@@ -0,0 +1,66 @@
1
+ # Physical Agent Architecture
2
+
3
+ `agent-physical` keeps physical-world concepts out of `agent-core` while still
4
+ making them available to normal `agent-core` agents.
5
+
6
+ ```text
7
+ Application
8
+ -> agent-core Agent
9
+ -> agent-physical tools
10
+ -> PhysicalSession
11
+ -> backend adapter
12
+ ```
13
+
14
+ The shared contract should stay small. It is allowed to know about physical
15
+ sessions, observations, capabilities, traces, outcomes, artifacts, and safety
16
+ policy. It should not know how to launch CaP-X as a Python Code-as-Policy
17
+ robotics framework, connect to ROS 2 robot middleware, authenticate to NVIDIA
18
+ Isaac Sim or another robot simulator, connect to robots_realtime for hardware
19
+ control, or send joint commands.
20
+
21
+ The agent loop stays above this package. `agent-core` or another harness decides
22
+ when to observe, how to reason over observations, whether to generate policy
23
+ code, whether to ask for approval, and whether to continue or stop. This package
24
+ only defines the shared physical vocabulary and generic tools those loops can
25
+ use.
26
+
27
+ ## What Belongs Here
28
+
29
+ - Backend-neutral session and observation types
30
+ - Generic tools for status, observe, stop, artifacts, and optional code
31
+ execution
32
+ - Safety metadata that can feed approval middleware and UIs
33
+ - Replay semantics for physical side effects
34
+
35
+ ## What Belongs In Adapters
36
+
37
+ - Process launch and lifecycle for a specific runtime
38
+ - Transport protocols and service clients
39
+ - Backend-specific artifact discovery
40
+ - Simulator or robot-specific observation mapping
41
+ - Backend-specific helper tools, such as turn history, skill libraries, or
42
+ visual frame access
43
+ - Any command vocabulary that only makes sense for one backend
44
+
45
+ ## CaP-X Mapping
46
+
47
+ CaP-X maps naturally as a backend adapter because it is already a Python
48
+ robotics framework for Code-as-Policy robot manipulation:
49
+
50
+ ```text
51
+ CaP-X YAML config -> PhysicalTaskSpec
52
+ CaP-X env/trial -> PhysicalSession
53
+ CaP-X render/logs -> PhysicalObservation
54
+ CaP-X outputs folder -> PhysicalArtifact[]
55
+ CaP-X reward/completed -> PhysicalOutcome
56
+ ```
57
+
58
+ The adapter should not duplicate CaP-X internals. It should launch, connect to,
59
+ or call CaP-X and translate the results into these contracts. For live
60
+ agent-owned CaP-X loops, the adapter should talk to a Python runtime bridge such
61
+ as `capx-agent-runtime`; `agent-physical` itself still only defines the generic
62
+ session and safety contract.
63
+
64
+ That split is what enables bring-your-own-agent. `agent-core` can use the
65
+ generic physical tools, the CaP-X adapter can add CaP-X-specific tools, and
66
+ CaP-X can remain the Python robotics runtime.
package/docs/safety.md ADDED
@@ -0,0 +1,31 @@
1
+ # Physical Safety
2
+
3
+ Physical tools are conservative by default.
4
+
5
+ Direct execution of policy code is marked:
6
+
7
+ - `riskLevel: "dangerous"`
8
+ - `destructive: true`
9
+ - `parallelSafe: false`
10
+ - `onInterrupt: "cancel"`
11
+ - replay mode `manual`
12
+ - side effect level `external`
13
+
14
+ That default is intentional. Replaying a tool call that moved a simulator or
15
+ robot can change state again, and replaying against hardware can be unsafe.
16
+
17
+ ## Approval Expectations
18
+
19
+ Applications should require explicit approval for hardware sessions and for any
20
+ capability that can cause motion, contact, heating, cutting, navigation, or
21
+ other physical side effects.
22
+
23
+ Simulation-only sessions can loosen the policy, but they should still treat
24
+ state-mutating execution as non-parallel and non-replayable unless the backend
25
+ provides snapshots and deterministic restore.
26
+
27
+ ## Stop Control
28
+
29
+ Every concrete `PhysicalSession` must implement `stop(reason)`. The exact
30
+ guarantee depends on the backend, but the method is the common control-plane
31
+ surface for UIs, middleware, and runtime interruption.
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@cuylabs/agent-physical",
3
+ "version": "5.0.2",
4
+ "description": "Physical-world agent contracts for sessions, observations, capabilities, safety, and tool adapters",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./tools": {
15
+ "types": "./dist/tools/index.d.ts",
16
+ "import": "./dist/tools/index.js",
17
+ "default": "./dist/tools/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "docs",
23
+ "README.md"
24
+ ],
25
+ "dependencies": {
26
+ "zod": "^3.25.76 || ^4.1.8",
27
+ "@cuylabs/agent-core": "^5.0.2"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.0.0",
31
+ "tsup": "^8.0.0",
32
+ "typescript": "^5.7.0",
33
+ "vitest": "^4.0.18"
34
+ },
35
+ "keywords": [
36
+ "agent",
37
+ "physical-ai",
38
+ "robotics",
39
+ "embodied-ai",
40
+ "tools",
41
+ "safety"
42
+ ],
43
+ "author": "cuylabs",
44
+ "license": "Apache-2.0",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/cuylabs-ai/agents-ts.git",
48
+ "directory": "packages/agent-physical"
49
+ },
50
+ "engines": {
51
+ "node": ">=20"
52
+ },
53
+ "publishConfig": {
54
+ "access": "public"
55
+ },
56
+ "scripts": {
57
+ "build": "tsup --config tsup.config.ts",
58
+ "dev": "tsup --config tsup.config.ts --watch",
59
+ "typecheck": "tsc --noEmit",
60
+ "test": "vitest run",
61
+ "test:watch": "vitest",
62
+ "clean": "rm -rf dist"
63
+ }
64
+ }