Task Evidence API
Session evidence, external files, host spans, HTTP requests, connectivity, and timeline annotations with capture-mode availability.
Use evidence APIs to inspect data retained for the task’s enforced session, capture accessible files, and attach findings to the timeline. A reader being available does not establish that a particular channel was captured. Empty, unknown, unavailable, and truncated results need explicit handling.
Availability by execution mode
| API | SDK mode | Device mode | Data or provider requirement |
|---|---|---|---|
ansight.session.getProperties, getTimeline | Yes | Yes | Properties and events retained by that session’s provider |
ansight.session.getAppState | Yes | Unavailable | Live app-state inspection |
ansight.logs, telemetry, artifacts, annotations | Yes | Yes | Relevant retained evidence; annotation writes need valid session evidence references |
ansight.ui.getVisualTreeSnapshot, searchVisualTree | Yes | Yes | Retained visual trees |
ansight.screenshots.getFrame | Yes | Yes | Retained screenshot frames |
ansight.network, connectivity, touches | Yes | Unavailable | Relevant HTTP, connectivity, or touch capture |
ansight.database.assert | Yes | Unavailable | Registered app database query tool |
ansight.files | Unavailable | Supported external file provider | iOS Simulator containers or accessible Android app data |
ansight.spans.measure | Yes | Yes | Host-observed events around an awaited operation |
These are the current task mode restrictions. Other host clients may read imported or completed captures, but tasks start against a live enforced session. Do not infer task availability from a CLI evidence command.
Evidence on virtual and physical devices
SDK capture depends on enabled SDK features and registered tools on either device kind. External capture has a different set of channels:
| External evidence | iOS Simulator | Physical iOS | Android Emulator | Physical Android |
|---|---|---|---|---|
| Screenshots and accessibility | Platform tools | Appium/XCUITest | ADB/UIAutomator | ADB/UIAutomator |
| Native app logs | Unified logs | Unavailable | Logcat | Logcat |
| Process CPU and memory | When readable | Optional Instruments export | When readable | When readable |
| Rendered FPS | Unavailable | Unavailable | Conditional on renderer statistics | Conditional on renderer statistics |
| Private sandbox files | Simulator containers | Unavailable for third-party apps | run-as or provisioned root ADB | run-as or provisioned root ADB |
| Recorded user touches / instrumented HTTP | SDK required | SDK required | SDK required | SDK required |
See external capture coverage for setup and metric semantics. External automation can send input without recording the user’s touches as an SDK touch stream.
Session, logs, telemetry, and artifacts
Use ansight.session.getTimeline() to correlate categories, ansight.logs to
inspect messages and exceptions, ansight.telemetry for samples and summaries,
and ansight.artifacts to locate retained snapshots and read their files.
The host method index lists each method.
ansight.touches analyzes SDK touch evidence; it does not synthesize a touch
stream from screenshots. ansight.database.assert queries app-exposed data and
needs a named task assertion on its result.
External sandbox files
ansight.files uses the host’s external provider. SDK file tools remain under
app.files. Require files.read for list or read, and files.capture for
capture.
All three methods take a root-relative path and optional root (default
"data"). An empty path lists the root. iOS also supports "app" and
"group:<identifier>"; Android supports "data" only. Traversal and symlinks
are refused. Android access needs run-as or an already provisioned root ADB
daemon.
read returns base64 content and defaults to a maximum of 256 KiB; it cannot
exceed that limit. capture defaults to 16 MiB and accepts maximumBytes up to
64 MiB, returning a retained snapshotId. Both return size, SHA-256, provider,
timestamps, and consistency: "best-effort-live-copy". The automatic monitor’s
exit-copy limit is separately fixed at 16 MiB per file.
Host-observed spans
ansight.spans.measure(name, asyncOperation, { group }?) brackets an operation
and emits <name>.started, <name>.completed, or <name>.failed events. It
uses two actions and requires host.spans. Use these events as Trends anchors
for automation, or native log anchors
for flows the app already logs.
Time windows
Network, log, telemetry, touch, annotation, artifact, and timeline methods accept their
typed argument contracts from ansight-task.d.ts. Time-bound contracts use
ISO-8601 UTC timestamps and bounded result limits. Prefer typed methods over
ansight.callTool because they inject the task session and return stable named
contracts.
Connectivity uses its own from, to, and at fields, which also accept
offsets from capture start. Its cursor behavior differs from HTTP pagination;
see the next section before sharing query helpers across these APIs.
Connectivity evidence
ansight.connectivity reads captured OS connection state, changes, quality
samples, and observation gaps. These task methods currently require SDK
mode and relevant connectivity capture. The host can also inspect imported
captures through other clients; that does not allow starting a task against
an offline session.
| Method | Use | Result |
|---|---|---|
ansight.connectivity.summary(args?) | Summarize a capture window | Availability durations, changes, disconnections, reconnections, gaps, quality samples and transports |
ansight.connectivity.timeline(args?) | Page through captured records | Matching records, counts, hasMore, and nextCursor |
ansight.connectivity.at(args) | Inspect state at a time or annotation | Observed state, availability, and measurement age; requires at or annotationId |
All return ConnectivityResult, including captured, recordCount,
malformedRecordCount, supportedMeasurements, effective capture/window bounds,
and rangeClipped. captured: false or availability: "unknown" is not proof
that the device was offline. A gap means observation was interrupted.
Arguments are from, to, at, annotationId, beforeSeconds,
afterSeconds, kind, limit, and cursor. Times accept ISO-8601 or
mm:ss / hh:mm:ss offsets from capture start. An annotation supplies a
default window of 120 seconds before and 30 seconds after it; either padding
accepts 1–3,600 seconds. kind filters snapshot, change, quality, or
gap. The default limit is 200; the maximum is 1,000.
const state = await ansight.connectivity.at({ at: "00:30" });
expect(state.captured, { id: "connectivity-was-captured" }).toBe(true);
expect(state.availability, { id: "connection-at-checkpoint" }).toBe("available");
Choose a checkpoint established by the workflow. OS connection availability does not prove that a particular server was reachable or a request succeeded; correlate with the HTTP request evidence below. Quality fields and transports depend on the platform and enabled SDK feature. See SDK connectivity capture.
For timeline pagination, repeat the same filters with cursor: nextCursor.
A changed live capture invalidates its cursor; start a new query if necessary.
HTTP cursors instead retain a fixed matching snapshot. at() can return
unknown when no observation covers the requested time; inspect measurement age
before relying on an old quality sample.
Connectivity inspection does not change the network. To apply TCP rate,
stall, or delay conditions use
ansight.device.network.
Captured network requests
ansight.network inspects HTTP capture records already received by the task’s
session. Its standard methods require no task.hostTools declaration. Calls
must be awaited serially, like other host methods.
const failures = await ansight.network.get({
methods: ["POST"],
query: "/checkout",
failedOnly: true,
limit: 20
});
const first = failures.requests[0];
if (first) {
const detail = await ansight.network.getRequest({ requestId: first.id });
const response = await ansight.network.readBody({
requestId: first.id,
side: "response",
maxBytes: 16 * 1024
});
// Header arrays preserve duplicate names; body content stays separately bounded.
console.log(detail.request.responseHeaders, detail.headersTruncated);
if (response.body !== null) {
console.log(response.body.encoding, response.body.data);
}
}
get accepts inclusive request-start startUtc/endUtc bounds, methods,
statuses, host, query, failedOnly, limit, and cursor. Different filters
combine with AND; values within methods or statuses combine with OR. Empty
arrays impose no restriction. Methods, hostname substrings, and text queries are
case-insensitive. Statuses accept integer codes from 100 through 599 or "1xx"
through "5xx". query searches URL, method, and error message. failedOnly: true
includes transport errors and HTTP statuses of at least 400; false imposes no
restriction. Invalid dates, reversed time ranges, and invalid filters reject the
call.
Pages contain complete summaries without header values or body content, ordered
newest first with a request-ID tie-breaker. The default limit is 200 and the
maximum is 1,000; the output budget can reduce the actual page size. Continue
with get({ cursor: page.nextCursor }) after checking nextCursor is non-null.
Cursors retain the initial matching snapshot, so live arrivals do not shift
subsequent pages.
The same filters may be repeated, but conflicting filters, a different session,
or an expired cursor reject. Snapshots expire five minutes after creation and
may be evicted earlier by the bounded host cache (32 snapshots, 16 Mi characters
of summary data). After expiry or eviction, start a new query without a cursor;
this also includes new arrivals. A matching snapshot that exceeds the cache
budget rejects with a request to narrow the filters. matchedRequestCount
describes the snapshot and isTruncated means matching records remain after
the page.
getRequest rejects unknown request IDs and returns metadata plus bounded
request/response header arrays. headersTruncated reports omitted complete
entries. readBody rejects unknown request IDs, but returns body: null when
the selected request has no retained body. A captured empty body instead has
data: "" and returnedByteCount: 0. Missing capture data does not explain why
content is unavailable.
maxBytes bounds decoded bytes, defaults to 16 KiB, and accepts 1 through 64 KiB.
Reads return a prefix that preserves UTF-8 boundaries; binary content uses Base64.
encoding identifies the representation, while capturedBytes, totalBytes,
and returnedByteCount distinguish capture metadata from this read. truncated
means capture omitted content; isTruncated means the read omitted retained
content. Both must be false for a complete body. Capture sanitization is preserved,
and body content is not automatically parsed as JSON. Metadata, headers, and
body previews are subject to the host’s serialized output budget; an individual
summary that cannot fit rejects explicitly.
Empty results do not prove capture is enabled or that an in-flight request has
completed. These methods inspect retained traffic; they do not initiate, replay,
intercept, or mock requests. Correlate network records with other evidence using
ansight.session.getTimeline({ categories: ["networkRequest"] }).
Timeline and screenshot annotations
An annotation has a timeline point or range and may include screenshot shapes
and a semantic visual-tree target. ansight.annotations.get(args?) keeps its
existing time, label, frameId, and hasGeometry filters. create, update,
and delete operate within the same enforced session and require no extra host
tool declarations.
const created = await ansight.annotations.create({
label: "Checkout failed",
startUtc: failedRequest.startedAtUtc,
endUtc: failedRequest.completedAtUtc,
notes: `${failedRequest.method} ${failedRequest.url}`,
geometries: [{
kind: "rectangle",
frameId: inspectedFrame.frameId,
x: 0.1, y: 0.65, width: 0.8, height: 0.12
}]
});
await ansight.annotations.update({
annotationId: created.annotationId,
expectedSource: created.annotation.source,
notes: "Response body reviewed.",
endUtc: null
});
// Remove the annotation if the task no longer needs it.
await ansight.annotations.delete({ annotationId: created.annotationId });
The example assumes the request and screenshot were inspected earlier in the
task; its coordinates are illustrative. Derive real shapes from the selected
frame. Annotation writes preserve evidence but do not establish task success;
use a named expect assertion after writing failure evidence.
create requires a non-whitespace label; it accepts optional annotationId,
notes, source, startUtc, endUtc, geometries, and target. It generates
an ID when omitted and atomically rejects an existing explicit ID. The default
source is task:<taskId>. An omitted start uses the session’s latest captured
timestamp; supply an evidence timestamp for reproducible placement. A generated
ID is not an idempotency key: reconcile an uncertain create before retrying.
update patches the latest saved record atomically. Omitted fields remain
unchanged. null clears notes, endUtc, or target; geometries: [] clears
shapes; a supplied geometry array replaces the entire array. Empty notes normalize
to no notes. Source, capture group, custom data, attached evidence, and hook
failures are preserved. The resulting end cannot precede its start, and equality
normalizes to a point. Timeline edits preserve actual screenshot capture times.
A no-op update succeeds and returns the saved record.
update and delete require an existing annotationId. Their optional
expectedSource is an exact-match guard checked atomically with the mutation;
a mismatch rejects without changing the record. This guard checks provenance,
not a revision. Concurrent patches preserve omitted fields; competing edits to
a supplied field use the last write. Mutations return the saved normalized
annotation, or deletedAnnotation after deletion. If the full saved or deleted
record exceeds 480,000 serialized characters, the call rejects before mutating
state. Existing host and CLI annotation operations remain available for large
legacy records.
Geometry inputs are typed point, rectangle, ellipse, or freeDraw records,
anchored by frameId. Coordinates are finite and normalized from 0 to 1 over
the full screenshot. Boxes need positive dimensions and must fit within the
image; free-draw paths need at least two points. Invalid geometry and styles
reject. The host resolves the frame’s capture timestamp and derives free-draw
bounds. Optional geometry fields are geometryId, text, strokeColor, and
strokeWidth. Stroke colors accept #RRGGBB or #AARRGGBB; stroke width must be
finite and positive.
A semantic target is { visualTreeSnapshotId, nodeId } from an inspected,
retained visual-tree snapshot. The host resolves its label, type, automation ID,
and bounds, and returns the node identity as target.targetId. Both frames and
trees must belong to the enforced session; references never silently capture
new evidence. Read results provide named geometry, target, inferred-shape, and
attached-evidence types. Output geometries also describe legacy line and arrow
shapes created by other host clients.