From a15ee4eff1d9e4c771cc91ea4db1ebdf5e4b8885 Mon Sep 17 00:00:00 2001 From: viambot <79611529+viambot@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:59:01 +0000 Subject: [PATCH 1/2] [WORKFLOW] AI update based on proto changes from commit da6c67ae811c5fcf30a225c707a28fb87afbc7d1 --- src/app/data-client.spec.ts | 2 +- src/services/data-manager/client.ts | 48 ++++++++++++++++- src/services/data-manager/data-manager.ts | 10 +++- src/services/motion/client.spec.ts | 66 ++++++++++++++++++++++- src/services/motion/client.ts | 1 + src/services/motion/motion.ts | 1 + src/services/motion/types.ts | 4 +- 7 files changed, 126 insertions(+), 6 deletions(-) diff --git a/src/app/data-client.spec.ts b/src/app/data-client.spec.ts index 10bdd17c8..912a99128 100644 --- a/src/app/data-client.spec.ts +++ b/src/app/data-client.spec.ts @@ -1715,4 +1715,4 @@ describe('DataPipelineClient tests', () => { expect(nextPage.runs).toEqual([]); }); }); -}); +}); \ No newline at end of file diff --git a/src/services/data-manager/client.ts b/src/services/data-manager/client.ts index 5e05b8c60..f2d92413d 100644 --- a/src/services/data-manager/client.ts +++ b/src/services/data-manager/client.ts @@ -1,7 +1,8 @@ import { Struct, type JsonValue } from '@bufbuild/protobuf'; import type { CallOptions, PromiseClient } from '@connectrpc/connect'; import { DataManagerService } from '../../gen/service/datamanager/v1/data_manager_connect.js'; -import { SyncRequest } from '../../gen/service/datamanager/v1/data_manager_pb.js'; +import { SyncRequest, UploadBinaryDataToDatasetsRequest, UploadBinaryDataToDatasetsResponse } from '../../gen/service/datamanager/v1/data_manager_pb.js'; +import { MimeType } from '../../gen/app/datasync/v1/data_sync_pb.js'; import type { RobotClient } from '../../robot'; import type { Options } from '../../types'; import { doCommandFromClient } from '../../utils'; @@ -80,4 +81,49 @@ export class DataManagerClient implements DataManager { callOptions ); } + + /** + * Uploads binary data to specified datasets. + * + * @example + * + * ```ts + * const dataManager = new VIAM.DataManagerClient( + * machine, + * 'my_data_manager' + * ); + * await dataManager.uploadBinaryDataToDatasets( + * new Uint8Array([1, 2, 3]), + * ['tag1', 'tag2'], + * ['datasetId1', 'datasetId2'], + * MimeType.MIME_TYPE_JPEG + * ); + * ``` + * + * @param binaryData - The binary data to upload. + * @param tags - Tags to associate with the binary data. + * @param datasetIds - IDs of the datasets to associate the binary data with. + * @param mimeType - The MIME type of the binary data. + * @param extra - Extra arguments to pass to the upload request. + * @param callOptions - Call options for the upload request. + */ + async uploadBinaryDataToDatasets( + binaryData: Uint8Array, + tags: string[], + datasetIds: string[], + mimeType: MimeType, + extra = {}, + callOptions = this.callOptions + ) { + const request = new UploadBinaryDataToDatasetsRequest({ + name: this.name, + binaryData, + tags, + datasetIds, + mimeType, + extra: Struct.fromJson(extra), + }); + this.options.requestLogger?.(request); + await this.client.uploadBinaryDataToDatasets(request, callOptions); + } } diff --git a/src/services/data-manager/data-manager.ts b/src/services/data-manager/data-manager.ts index 41ab8828f..ba0d77a67 100644 --- a/src/services/data-manager/data-manager.ts +++ b/src/services/data-manager/data-manager.ts @@ -1,6 +1,14 @@ import type { Struct } from '@bufbuild/protobuf'; import type { Resource } from '../../types'; +import type { MimeType } from '../../app/datasync/v1/data_sync_pb.js'; export interface DataManager extends Resource { sync: (extra?: Struct) => Promise; -} + uploadBinaryDataToDatasets: ( + binaryData: Uint8Array, + tags: string[], + datasetIds: string[], + mimeType: MimeType, + extra?: Struct + ) => Promise; +} \ No newline at end of file diff --git a/src/services/motion/client.spec.ts b/src/services/motion/client.spec.ts index 6c7e7190f..743c12ec7 100644 --- a/src/services/motion/client.spec.ts +++ b/src/services/motion/client.spec.ts @@ -18,9 +18,10 @@ import { ListPlanStatusesRequest, MoveOnGlobeRequest, MoveOnGlobeResponse, + MoveRequest, StopPlanRequest, } from '../../gen/service/motion/v1/motion_pb'; -import { GeoGeometry, GeoPoint, ResourceName } from '../../types'; +import { GeoGeometry, GeoPoint, Pose, PoseInFrame, ResourceName } from '../../types'; import { MotionClient } from './client'; import { GetPlanResponse, @@ -29,6 +30,7 @@ import { ObstacleDetector, PlanState, } from './types'; +import { Constraints, PseudolinearConstraint } from './types'; const motionClientName = 'test-motion'; const date = new Date(1970, 1, 1, 1, 1, 1); @@ -263,6 +265,66 @@ describe('moveOnGlobe', () => { }); }); +describe('move', () => { + it('sends a move request with pseudolinear constraints', async () => { + const expectedComponentName = new ResourceName({ + namespace: 'viam', + type: 'component', + subtype: 'base', + name: 'myBase', + }); + const expectedDestination: PoseInFrame = { + referenceFrame: 'world', + pose: { + x: 1, + y: 2, + z: 3, + oX: 0, + oY: 0, + oZ: 1, + theta: 90, + }, + }; + const expectedPseudolinearConstraint = new PseudolinearConstraint({ + lineToleranceFactor: 0.5, + orientationToleranceFactor: 0.1, + }); + const expectedConstraints: Constraints = { + pseudolinearConstraint: [expectedPseudolinearConstraint], + }; + const expectedExtra = { some: 'extra' }; + let capturedReq: MoveRequest | undefined; + const mockTransport = createRouterTransport(({ service }) => { + service(MotionService, { + move: (req) => { + capturedReq = req; + return { success: true }; + }, + }); + }); + RobotClient.prototype.createServiceClient = vi + .fn() + .mockImplementation(() => + createPromiseClient(MotionService, mockTransport) + ); + motion = new MotionClient(new RobotClient('host'), motionClientName); + await expect( + motion.move( + expectedDestination, + expectedComponentName, + undefined, // worldState + expectedConstraints, + expectedExtra + ) + ).resolves.toStrictEqual(true); + expect(capturedReq?.name).toStrictEqual(motionClientName); + expect(capturedReq?.destination).toStrictEqual(expectedDestination); + expect(capturedReq?.componentName).toStrictEqual(expectedComponentName); + expect(capturedReq?.constraints).toStrictEqual(expectedConstraints); + expect(capturedReq?.extra).toStrictEqual(Struct.fromJson(expectedExtra)); + }); +}); + describe('stopPlan', () => { it('return null', async () => { const expectedComponentName = new ResourceName({ @@ -525,4 +587,4 @@ describe('listPlanStatuses', () => { expect(capturedReq?.onlyActivePlans).toStrictEqual(expectedOnlyActivePlans); expect(capturedReq?.extra).toStrictEqual(Struct.fromJson(expectedExtra)); }); -}); +}); \ No newline at end of file diff --git a/src/services/motion/client.ts b/src/services/motion/client.ts index 588b8357b..1d3a1e9c4 100644 --- a/src/services/motion/client.ts +++ b/src/services/motion/client.ts @@ -9,6 +9,7 @@ import { MoveOnMapRequest, MoveRequest, StopPlanRequest, + PseudolinearConstraint, } from '../../gen/service/motion/v1/motion_pb'; import type { RobotClient } from '../../robot'; import type { diff --git a/src/services/motion/motion.ts b/src/services/motion/motion.ts index b072f8381..37b80d030 100644 --- a/src/services/motion/motion.ts +++ b/src/services/motion/motion.ts @@ -15,6 +15,7 @@ import type { GetPlanResponse, ListPlanStatusesResponse, MotionConfiguration, + PseudolinearConstraint, } from './types'; /** diff --git a/src/services/motion/types.ts b/src/services/motion/types.ts index 704fcb230..65c4d51b5 100644 --- a/src/services/motion/types.ts +++ b/src/services/motion/types.ts @@ -6,6 +6,7 @@ export type CollisionSpecification = export type Constraints = PlainMessage; export type GetPlanResponse = motionApi.GetPlanResponse; export type LinearConstraint = PlainMessage; +export type PseudolinearConstraint = PlainMessage; export type ListPlanStatusesResponse = motionApi.ListPlanStatusesResponse; export type MotionConfiguration = PlainMessage; export type ObstacleDetector = PlainMessage; @@ -18,9 +19,10 @@ export const { Constraints, GetPlanResponse, LinearConstraint, + PseudolinearConstraint, ListPlanStatusesResponse, MotionConfiguration, ObstacleDetector, OrientationConstraint, PlanState, -} = motionApi; +} = motionApi; \ No newline at end of file From 0ded13ce2ed0bccb067c83440a873444e2192239 Mon Sep 17 00:00:00 2001 From: Naveed Jooma Date: Wed, 27 Aug 2025 12:37:00 -0400 Subject: [PATCH 2/2] Fix AI things --- src/app/data-client.spec.ts | 2 +- src/services/data-manager/client.ts | 47 ++++++++------- src/services/data-manager/data-manager.ts | 4 +- src/services/motion/client.spec.ts | 72 +++++++++-------------- src/services/motion/client.ts | 1 - src/services/motion/motion.ts | 1 - src/services/motion/types.ts | 5 +- 7 files changed, 60 insertions(+), 72 deletions(-) diff --git a/src/app/data-client.spec.ts b/src/app/data-client.spec.ts index 912a99128..10bdd17c8 100644 --- a/src/app/data-client.spec.ts +++ b/src/app/data-client.spec.ts @@ -1715,4 +1715,4 @@ describe('DataPipelineClient tests', () => { expect(nextPage.runs).toEqual([]); }); }); -}); \ No newline at end of file +}); diff --git a/src/services/data-manager/client.ts b/src/services/data-manager/client.ts index f2d92413d..320ae8ab5 100644 --- a/src/services/data-manager/client.ts +++ b/src/services/data-manager/client.ts @@ -1,15 +1,18 @@ import { Struct, type JsonValue } from '@bufbuild/protobuf'; -import type { CallOptions, PromiseClient } from '@connectrpc/connect'; -import { DataManagerService } from '../../gen/service/datamanager/v1/data_manager_connect.js'; -import { SyncRequest, UploadBinaryDataToDatasetsRequest, UploadBinaryDataToDatasetsResponse } from '../../gen/service/datamanager/v1/data_manager_pb.js'; +import type { CallOptions, Client } from '@connectrpc/connect'; import { MimeType } from '../../gen/app/datasync/v1/data_sync_pb.js'; +import { DataManagerService } from '../../gen/service/datamanager/v1/data_manager_connect.js'; +import { + SyncRequest, + UploadBinaryDataToDatasetsRequest, +} from '../../gen/service/datamanager/v1/data_manager_pb.js'; import type { RobotClient } from '../../robot'; import type { Options } from '../../types'; import { doCommandFromClient } from '../../utils'; import type { DataManager } from './data-manager'; export class DataManagerClient implements DataManager { - private client: PromiseClient; + private client: Client; public readonly name: string; private readonly options: Options; public callOptions: CallOptions = { headers: {} as Record }; @@ -108,22 +111,22 @@ export class DataManagerClient implements DataManager { * @param callOptions - Call options for the upload request. */ async uploadBinaryDataToDatasets( - binaryData: Uint8Array, - tags: string[], - datasetIds: string[], - mimeType: MimeType, - extra = {}, - callOptions = this.callOptions - ) { - const request = new UploadBinaryDataToDatasetsRequest({ - name: this.name, - binaryData, - tags, - datasetIds, - mimeType, - extra: Struct.fromJson(extra), - }); - this.options.requestLogger?.(request); - await this.client.uploadBinaryDataToDatasets(request, callOptions); - } + binaryData: Uint8Array, + tags: string[], + datasetIds: string[], + mimeType: MimeType, + extra = {}, + callOptions = this.callOptions + ) { + const request = new UploadBinaryDataToDatasetsRequest({ + name: this.name, + binaryData, + tags, + datasetIds, + mimeType, + extra: Struct.fromJson(extra), + }); + this.options.requestLogger?.(request); + await this.client.uploadBinaryDataToDatasets(request, callOptions); + } } diff --git a/src/services/data-manager/data-manager.ts b/src/services/data-manager/data-manager.ts index ba0d77a67..1d7942e70 100644 --- a/src/services/data-manager/data-manager.ts +++ b/src/services/data-manager/data-manager.ts @@ -1,6 +1,6 @@ import type { Struct } from '@bufbuild/protobuf'; +import { MimeType } from '../../gen/app/datasync/v1/data_sync_pb.js'; import type { Resource } from '../../types'; -import type { MimeType } from '../../app/datasync/v1/data_sync_pb.js'; export interface DataManager extends Resource { sync: (extra?: Struct) => Promise; @@ -11,4 +11,4 @@ export interface DataManager extends Resource { mimeType: MimeType, extra?: Struct ) => Promise; -} \ No newline at end of file +} diff --git a/src/services/motion/client.spec.ts b/src/services/motion/client.spec.ts index 743c12ec7..1bd7d7517 100644 --- a/src/services/motion/client.spec.ts +++ b/src/services/motion/client.spec.ts @@ -8,10 +8,7 @@ vi.mock('../../gen/service/motion/v1/motion_pb_service'); vi.mock('../../robot'); import { Struct, Timestamp } from '@bufbuild/protobuf'; -import { - createPromiseClient, - createRouterTransport, -} from '@connectrpc/connect'; +import { createClient, createRouterTransport } from '@connectrpc/connect'; import { MotionService } from '../../gen/service/motion/v1/motion_connect'; import { GetPlanRequest, @@ -21,16 +18,23 @@ import { MoveRequest, StopPlanRequest, } from '../../gen/service/motion/v1/motion_pb'; -import { GeoGeometry, GeoPoint, Pose, PoseInFrame, ResourceName } from '../../types'; +import { + GeoGeometry, + GeoPoint, + Pose, + PoseInFrame, + ResourceName, +} from '../../types'; import { MotionClient } from './client'; import { + Constraints, GetPlanResponse, ListPlanStatusesResponse, MotionConfiguration, ObstacleDetector, PlanState, + PseudolinearConstraint, } from './types'; -import { Constraints, PseudolinearConstraint } from './types'; const motionClientName = 'test-motion'; const date = new Date(1970, 1, 1, 1, 1, 1); @@ -78,9 +82,7 @@ describe('moveOnGlobe', () => { RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); @@ -228,9 +230,7 @@ describe('moveOnGlobe', () => { RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); @@ -273,9 +273,9 @@ describe('move', () => { subtype: 'base', name: 'myBase', }); - const expectedDestination: PoseInFrame = { + const expectedDestination = new PoseInFrame({ referenceFrame: 'world', - pose: { + pose: new Pose({ x: 1, y: 2, z: 3, @@ -283,15 +283,15 @@ describe('move', () => { oY: 0, oZ: 1, theta: 90, - }, - }; + }), + }); const expectedPseudolinearConstraint = new PseudolinearConstraint({ - lineToleranceFactor: 0.5, - orientationToleranceFactor: 0.1, + lineToleranceFactor: 5, + orientationToleranceFactor: 10, }); - const expectedConstraints: Constraints = { + const expectedConstraints = new Constraints({ pseudolinearConstraint: [expectedPseudolinearConstraint], - }; + }); const expectedExtra = { some: 'extra' }; let capturedReq: MoveRequest | undefined; const mockTransport = createRouterTransport(({ service }) => { @@ -304,15 +304,13 @@ describe('move', () => { }); RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); await expect( motion.move( expectedDestination, expectedComponentName, - undefined, // worldState + undefined, expectedConstraints, expectedExtra ) @@ -347,9 +345,7 @@ describe('stopPlan', () => { RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); @@ -380,9 +376,7 @@ describe('stopPlan', () => { RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); @@ -455,9 +449,7 @@ describe('getPlan', () => { RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); @@ -492,9 +484,7 @@ describe('getPlan', () => { RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); @@ -547,9 +537,7 @@ describe('listPlanStatuses', () => { RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); @@ -575,9 +563,7 @@ describe('listPlanStatuses', () => { RobotClient.prototype.createServiceClient = vi .fn() - .mockImplementation(() => - createPromiseClient(MotionService, mockTransport) - ); + .mockImplementation(() => createClient(MotionService, mockTransport)); motion = new MotionClient(new RobotClient('host'), motionClientName); @@ -587,4 +573,4 @@ describe('listPlanStatuses', () => { expect(capturedReq?.onlyActivePlans).toStrictEqual(expectedOnlyActivePlans); expect(capturedReq?.extra).toStrictEqual(Struct.fromJson(expectedExtra)); }); -}); \ No newline at end of file +}); diff --git a/src/services/motion/client.ts b/src/services/motion/client.ts index 1d3a1e9c4..588b8357b 100644 --- a/src/services/motion/client.ts +++ b/src/services/motion/client.ts @@ -9,7 +9,6 @@ import { MoveOnMapRequest, MoveRequest, StopPlanRequest, - PseudolinearConstraint, } from '../../gen/service/motion/v1/motion_pb'; import type { RobotClient } from '../../robot'; import type { diff --git a/src/services/motion/motion.ts b/src/services/motion/motion.ts index 37b80d030..b072f8381 100644 --- a/src/services/motion/motion.ts +++ b/src/services/motion/motion.ts @@ -15,7 +15,6 @@ import type { GetPlanResponse, ListPlanStatusesResponse, MotionConfiguration, - PseudolinearConstraint, } from './types'; /** diff --git a/src/services/motion/types.ts b/src/services/motion/types.ts index 65c4d51b5..0414a5da9 100644 --- a/src/services/motion/types.ts +++ b/src/services/motion/types.ts @@ -6,7 +6,8 @@ export type CollisionSpecification = export type Constraints = PlainMessage; export type GetPlanResponse = motionApi.GetPlanResponse; export type LinearConstraint = PlainMessage; -export type PseudolinearConstraint = PlainMessage; +export type PseudolinearConstraint = + PlainMessage; export type ListPlanStatusesResponse = motionApi.ListPlanStatusesResponse; export type MotionConfiguration = PlainMessage; export type ObstacleDetector = PlainMessage; @@ -25,4 +26,4 @@ export const { ObstacleDetector, OrientationConstraint, PlanState, -} = motionApi; \ No newline at end of file +} = motionApi;