Skip to content

Commit df29115

Browse files
committed
Update SDK to version 0.43.0
1 parent 2a39dfe commit df29115

36 files changed

Lines changed: 3179 additions & 177 deletions

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
11
# Changelog
22

3+
# 0.43.0
4+
## Breaking Changes
5+
- `ClientToolSpec.name` must now match `^client_[a-z][a-z0-9_]*$`. Names without the `client_` prefix are rejected at deserialization, so the API returns 400 before persisting any session state. This also applies to `@client_tool`-decorated functions, since the decorator defaults the tool name to `fn.__name__`. Either rename the function (e.g. `def client_store_fact`) or pass `name="client_..."` explicitly.
6+
- `AgentSessionGoalRecord` now requires a `message_sequence_num: int` field. The field is the session-wide message-sequence index of the USER-role message that declared the goal — clients use it to render goal chips adjacent to the turn they were attached to. External consumers that construct the record directly (test fixtures, custom middleware, recorded API responses) will fail validation on upgrade until they pass the new field. In-tree consumers and SDK-side `to_agent_goal()` re-hydration from server responses are unaffected, since the server populates the field on every record it emits.
7+
8+
## Features Added
9+
- **Sessions (experimental):** Represent an activity — a drone flight, a vehicle drive, a robot arm test run — as a `Session`: an operational time window over zero, one, or many Devices. Create one with `Session.create(name=..., device_ids=...)`, or use the anchored-convenience constructors `Device.create_session(name=...)` and `Dataset.create_session(name=..., ...)`. Include files with `Session.add_file` / `add_files` (each optionally narrowed to a sub-window via `range_min_timestamp_ns` / `range_max_timestamp_ns`), and attach to additional devices via `Session.attach_to_device(device_id)`. Each operation has a symmetric counterpart: removing files, detaching devices, renaming, and deleting. The Session's `min_timestamp_ns` / `max_timestamp_ns` (Unix-epoch nanoseconds) are recomputed on every file add or remove. Enumerate Sessions with `Session.for_dataset`, `Session.for_org`, `Dataset.get_sessions()`, or `Device.list_sessions()`. `Session.list_topics()` iterates every topic reachable through the Session's files, turning "all signals from this flight / drive / run" into a single query. Because a Session is bounded by the activity rather than the recordings, it may span many files or cover only part of one.
10+
- **Content-addressable topic schemas (experimental):** A `Topic`'s field structure is now represented as a `TopicSchema` identified by a checksum over its fields. Topics whose fields share the same names, paths, and data types reference the same schema within an organization. Retrieve a topic's schema with `Topic.get_schema()`, or look one up directly via `TopicSchema.for_topic(topic_id)` / `TopicSchema.from_id(schema_id)`. Lays the groundwork for finding every topic in an org with a given shape, and for comparing topics across files, sessions, and devices.
11+
- **Timeline offsets on files (experimental):** `File.set_timeline_offset(unix_epoch_offset_ns, ...)` — and its batched counterpart `File.set_timeline_offsets([...])` — project a file's stored partition timestamps onto Unix-epoch wall-clock (`session_time_ns = stored_time_ns + unix_epoch_offset_ns`) without re-ingest. An offset can be narrowed by topic (`topic` / `topic_name`) and by timeline source (`timeline_source` / `timeline_source_name`). `TimelineSourceKind` names where a timestamp comes from: a field in the message (`schema_field`, e.g. `header.stamp`), the recorder-assigned log time (`message_log_time`), or the publisher-assigned publish time (`message_publish_time`). The same API is available on `Topic` (`Topic.set_timeline_offset` / `set_timeline_offsets`), auto-scoped to a single topic. A bag that starts at zero, a sensor that logs in device-uptime, or a camera that lags the IMU by a few milliseconds can be reconciled after ingest. Session aggregate bounds read from these projected timestamps.
12+
- `AgentSession.submit_feedback(message_sequence_num, sentiment, categories=[...], notes=None)` persists structured feedback on a specific assistant message. `sentiment` is `FeedbackSentiment.POSITIVE` or `NEGATIVE`; `categories` is a list of `FeedbackCategory` values (multi-select) that must match the selected sentiment. `FeedbackCategory.OTHER` requires `notes`. Resubmitting from the same user on the same message overwrites `sentiment`, `categories`, and `notes` on the existing row rather than creating a duplicate. Replaces the previous write-only Slack-only feedback path with a durable, queryable record.
13+
- `AgentSession.fork(message_sequence_num)` forks a session at a given message into a new session owned by the caller. Available to the session's creator for their own sessions and to Roboto admins for any session. The new session carries the source's `org_id`; lineage is tracked on `AgentSessionRecord.forked_from_session_id` and `AgentSessionRecord.forked_from_message_sequence_num`.
14+
- Added `FeedbackSentiment`, `FeedbackCategory`, `SubmitFeedbackRequest`, and `AdminUpdateFeedbackRequest` models to `roboto.ai.agent_session` for programmatic access to AI chat feedback. (`AgentFeedbackRecord`, the admin-triage shape, is intentionally not part of the public surface.)
15+
- `AgentSessionRecord` now exposes `forked_from_session_id` and `forked_from_message_sequence_num` fields. Both are `None` for sessions that were not created via `AgentSession.fork`.
16+
- `Topic.get_data` and `Topic.get_data_as_df` accept an optional `representation_selector` (`RepresentationSelector`) to choose among multiple representations. Defaults to raw, untransformed data; filter on `content_format` or `transformations` to match a specific encoding or transformation pipeline.
17+
- `Topic.set_default_representation` and `Topic.add_message_path_representation` accept optional `format` and `transformations` to describe a representation.
18+
- `RepresentationRecord` exposes a new `format` field.
19+
- New `AnalysisScope` in `roboto.ai.core` captures a time window (`start_time` / `end_time`, nanoseconds since the Unix epoch) that scopes which data the agent's tools may consider. `AgentSession.start()`, `.send()`, and `.send_text()` accept an `analysis_scope=` kwarg; on `start` it attaches the scope to the session, on `send`/`send_text` an explicit value replaces the session's current scope (omitting the kwarg leaves it untouched). The scope is persisted on the session and delivered to every tool invocation on the server side. The `analyze_topic` tool honors the scope today by clamping topic data to the window; other tools will opt in as they adopt.
20+
- New `RobotoFeatureNotAvailableException` in `roboto.exceptions`, raised when an API call targets a route gated by a feature flag that is not enabled for the caller.
21+
- **AgentSession can now declare hard, verifiable goals per turn.** New `goals=` parameter on `AgentSession.start()`, `.send()`, and `.send_text()` accepts a list of typed goal models from the closed `roboto.ai.goals.AgentGoal` union (capped at 5 entries per turn). The agent runner enforces achievement: it re-prompts up to 3 times if the LLM ends a turn without satisfying every declared goal, then reports the new `AgentSessionStatus.GOALS_FAILED` terminal status (which `AgentSession.run()` raises as a typed `RobotoAgentGoalsFailedException`). The `message`/`messages` parameter becomes optional when `goals=` is provided. Authorization runs at goal-registration time so the caller gets a fast 401 before any model resources are spent. Two concrete goals ship in this release: `DatasetSummaryAgentGoal(dataset_id, summary_format_spec_prompt)` directs the agent to investigate a dataset and persist a summary via `SummaryService.set_dataset_summary`; `DatasetTriageGoal(dataset_id, label_vocabulary={label: description, ...})` directs the agent to deliberate over each label in the vocabulary and apply the ones that fit (zero or more) as dataset tags. `AgentSessionRecord.goals` exposes the per-goal status (`PENDING` / `ACHIEVED` / `FAILED`) and `AgentSessionGoalRecord.to_agent_goal()` re-hydrates the typed goal model from any read. Each `AgentSessionGoalRecord` also carries a `message_sequence_num: int` identifying the USER-role message that declared the goal, so clients can render goal chips adjacent to the turn they were attached to. The corresponding `AgentSessionDelta` now exposes a `goals` field so streaming consumers see goal-status transitions land alongside message and status deltas.
22+
- `RobotoLLMContext` is deprecated and renamed to `ClientViewingContext` (parameter `client_context` on `AgentSession.start()`, `.send()`, and `.send_text()`, replacing the previous `context=` parameter that took a `RobotoLLMContext`). The rename disambiguates the SDK call site now that `goals` and `analysis_scope` are also turn-level inputs — "context" was overloaded to mean both the goal/scope envelope and the client-side viewing state. The old name is still importable from `roboto.ai.core` and `roboto.ai.agent_session` for one release as a re-export of `ClientViewingContext`; the wire-format `client_context` field also accepts the legacy `context` JSON key for one release via `validation_alias=AliasChoices("client_context", "context")`. Both compatibility aliases will be removed in a subsequent release — migrate to `from roboto.ai.core import ClientViewingContext` and pass it via `client_context=`.
23+
- Collections now support `event` resources. `CollectionResourceType.Event` works with `Collection.create(resource_type=CollectionResourceType.Event, event_ids=[...])`, `Collection.from_id(...)`, and the `Collection.events`, `add_event()`, and `remove_event()` helpers. The CLI now accepts `--event-id` for `roboto collections create` and `--add-event-id` / `--remove-event-id` for `roboto collections update <collection_id>`.
24+
25+
## Behavior Changes
26+
- **BYOB cross-org access now returns `RobotoNotFoundException` (404) instead of `RobotoUnauthorizedException` (401).** With the integrations table now keyed on `(org_id, bucket_name)`, looking up a bucket registered only under another org no longer surfaces that registration's existence; it surfaces as not-found, matching the security posture of the rest of the org-scoped API. Affects `Dataset.get_single_bucket_creds`, `File.import_one`, `File.import_batch`, `File.delete`, `File.get_signed_upload_url`, and `File.get_signed_url`. Callers that switch on exception type (rather than surfacing the message) should add `RobotoNotFoundException` to their cross-org branch.
27+
28+
## Bugs Fixed
29+
- `get_data` and `get_data_as_df` now return full-resolution image data for topics ingested by the updated `ros_ingestion` action; previously they returned a downsampled, re-encoded version.
30+
331
# 0.42.0
432
## Features Added
533
- New `AnalysisScope` in `roboto.ai.core` captures a time window (`start_time` / `end_time`, nanoseconds since the Unix epoch) that scopes which data the agent's tools may consider. `AgentSession.start()`, `.send()`, and `.send_text()` accept an `analysis_scope=` kwarg; on `start` it attaches the scope to the session, on `send`/`send_text` an explicit value replaces the session's current scope (omitting the kwarg leaves it untouched). The scope is persisted on the session and delivered to every tool invocation on the server side. The `analyze_topic` tool honors the scope today by clamping topic data to the window; other tools will opt in as they adopt.

0 commit comments

Comments
 (0)