Files
Artemis-Eapil/docs/design/video-analysis-memory.md
T

607 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ARTEMIS Video Analysis Memory and Reliability Design
Status: implemented (2026-08-25)
Audience: ARTEMIS runtime, perception, tracing, and mobile automation maintainers
## 1. Executive summary
The current video analyzer treats its blackboard as state owned by one
`VideoAnalyzer` object. Tool invocations create new analyzer objects, so the
state is lost between calls. A failed parent analysis also discards useful
work completed by child analyzers. Overlap detection is advisory and does not
prevent the same interval from being sent to a video model again.
This design moves video memory out of the agent and into a video-scoped,
persistent blackboard. The blackboard is the source of truth for:
- which intervals have been analyzed for a normalized query and modality;
- observations and evidence extracted from those intervals;
- successful, running, and failed segment attempts;
- resumable partial results across tool calls;
- concurrency leases that prevent duplicate model requests.
The analyzer becomes a coordinator over this state. It calculates the set
difference between a requested interval and completed coverage, analyzes only
the gaps, commits every successful chunk immediately, and returns partial
results without erasing prior work.
The first implementation deliberately uses SQLite and the existing trace
directory. Vector search, semantic graphs, provider-managed context caches,
and entity re-identification are future layers, not prerequisites for fixing
correctness and reliability.
## 2. Goals
### 2.1 Functional goals
1. Share analyzed intervals and results across every `VideoAnalyzer` created
for the same recording.
2. Avoid repeating an identical successful `(video, interval, query,
modality)` analysis.
3. Persist each successful chunk before sibling chunks or the parent agent
finish.
4. Preserve successful chunks when some chunks fail.
5. Expose previous observations to both native Gemini and universal-model
coordinators.
6. Keep evidence tied to recording-relative timestamps and durable files.
7. Prevent concurrent duplicate requests with an expiring lease.
8. Maintain existing public tool signatures.
### 2.2 Reliability goals
- A process or model failure may lose only the currently running chunk.
- An expired running lease is reclaimable.
- Retrying a request analyzes only uncovered or failed chunks.
- A partial result explicitly identifies failed intervals.
- SQLite writes are idempotent and safe under multiple analyzer instances.
- Evidence used by persistent memory is not deleted by temporary-file cleanup.
### 2.3 Non-goals for phase one
- Semantic similarity reuse between materially different queries.
- Cross-recording memory or user identity memory.
- Replacing Gemini or the configured universal VLM.
- Hosting an open-weight video model or accessing model KV caches.
- Full WorldMM semantic graphs, HippoRAG, VLM2Vec, or ReflectWorld ReID.
- Permanent retention of uploaded provider files.
## 3. Current failure modes
### 3.1 Agent-owned state
`VideoAnalyzer.__init__` initializes an empty list. `video_tool.py` creates a
new analyzer for every tool call. Consequently, a later invocation cannot see
the earlier invocation's ledger.
### 3.2 Advisory overlap handling
The analyzer calculates high-overlap warnings but continues with extraction,
compression, upload, and inference. A warning in a prompt is not an
idempotency mechanism.
### 3.3 Commit-at-the-end behavior
Some event observations are appended during child analysis, but they are only
in memory. If the parent fails or cleanup runs, the trace can contain expensive
model activity with no reusable result.
### 3.4 Mutable recording ambiguity
An open-ended interval is currently cached as `(start, None)`. The meaning of
`None` changes while recording continues, so this cannot be a stable cache
identity.
### 3.5 Disposable evidence
Extracted screenshots live in temporary directories registered for cleanup.
The ledger may therefore reference files that no longer exist.
## 4. Design principles
### 4.1 Memory before reasoning
Perception results are written before the coordinator generates its final
answer. Answer generation reads stored evidence; it is not the owner of that
evidence.
### 4.2 Evidence-backed records
Every observation carries an interval, query, confidence, modality, model
metadata where available, and an optional durable screenshot. Summaries never
stand alone without temporal provenance.
### 4.3 Objective observation versus query result
The design has two logical layers:
- **Observations** describe visible or audible events and can help later
queries.
- **Segment results** answer one normalized query over one complete interval
and define exact reusable coverage.
An observation about a button is useful context for many questions, but a
segment result for "did login succeed" must not automatically satisfy a
different query such as "how long did the spinner remain visible".
### 4.4 Immutable interval identity
An analysis segment always has numeric start and end timestamps. Open-ended
requests are resolved to the safe available end before they are claimed or
committed.
### 4.5 At-least-once execution, idempotent commit
Provider requests can be retried. Database constraints and deterministic keys
make commits idempotent. Exact-once provider execution is not promised, but
duplicate execution is strongly suppressed by leases.
## 5. Architecture
```text
video_analyzer tool
|
v
VideoAnalyzer coordinator ---------> persistent blackboard ledger
| | |
| | +-- observations/evidence
| +-- segment coverage and attempts
|
+-- resolve stable numeric interval
+-- subtract completed coverage
+-- claim uncovered chunks with leases
+-- run child analysis
+-- commit each successful chunk immediately
+-- mark failed chunks retryable
+-- synthesize cached + new + partial results
```
The blackboard is acquired from `ArtemisContext`, not constructed as private
agent state. Multiple analyzers in the same context share the object, while
SQLite makes the data available to later instances and process restarts.
## 6. Recording identity
The preferred blackboard key is the active `RecordingSession.video_id`:
```text
video:<uuid>
```
If no active recording is available, the fallback is the DataEngine session:
```text
session:<uuid>
```
The context retains the resolved blackboard instance so analysis after a
recording stops continues to use the same key. Extracted recording artifacts
also carry an explicit source revision:
```text
<video-uuid>:<generation>:<sealed-end>
```
A generation advances whenever the recorder rolls a physical segment. The
recorder tracks the sealed numeric prefix, and every `end=None` analysis is
resolved to the current safe numeric end before it is claimed.
## 7. Persistence model
### 7.1 `video_analysis_segments`
One row represents a complete query-specific analysis of a numeric interval.
| Column | Meaning |
| --- | --- |
| `board_key` | Recording/session namespace |
| `query_key` | SHA-256 of the normalized query |
| `query_text` | Original query for debugging and retrieval |
| `modality` | `video` or `audio` |
| `start_ms`, `end_ms` | Stable integer interval |
| `status` | `running`, `succeeded`, `retryable_failed`, `permanent_failed` |
| `lease_owner`, `lease_expires_at` | Duplicate-work suppression |
| `attempt_count` | Number of acquired attempts |
| `summary`, `analysis` | Reusable completed result |
| `error` | Last structured failure text |
| `created_at`, `updated_at` | Audit timestamps |
The unique key is:
```text
(board_key, query_key, modality, start_ms, end_ms)
```
### 7.2 `video_analysis_observations`
One row represents a timestamped event or fact.
| Column | Meaning |
| --- | --- |
| `observation_id` | Deterministic content fingerprint |
| `board_key` | Recording/session namespace |
| `start_ms`, `end_ms` | Event interval |
| `query_text` | Query that caused extraction |
| `summary` | Concise observation |
| `confidence` | Model-reported confidence |
| `modality` | `video` or `audio` |
| `screenshot_path` | Durable evidence path |
| `extra_json` | Forward-compatible metadata |
| `created_at` | Audit timestamp |
The deterministic observation ID makes repeated commits safe.
### 7.3 Evidence layout
```text
<trace-session>/video_blackboard/evidence/<content-id>.jpg
```
Temporary screenshots are copied into this directory before their source is
registered for deletion. Stored records reference the durable copy.
## 8. Segment state machine
```text
lease expires
running ------------------------------+
| |
| success v
+----------> succeeded retryable_failed
| |
| retryable error | claim again
+----------> retryable_failed ------+
|
| non-retryable/budget exhausted
+----------> permanent_failed
```
Claim behavior is transactional:
1. A missing row is inserted as `running`.
2. `succeeded` returns its cached result without acquiring work.
3. `running` with a live lease returns `in_progress`.
4. An expired lease or retryable failure is atomically reclaimed and increments
`attempt_count`.
Exhausted failures store a normalized category and category-derived
retryability. Permanent failure is reserved for validated bad input,
authentication/policy errors, cancellation, or explicit decisions.
## 9. Coverage and planning
Coverage is query- and modality-specific. Given requested interval `R` and
the union of successful intervals `S`, the work planner calculates:
```text
missing = R - union(S)
```
Each missing interval is split into bounded chunks. Completed chunks are
included in the returned result; only gaps are sent to the provider.
Interval math uses integer milliseconds internally to prevent floating-point
key drift. API-facing timestamps remain seconds.
Observations from other queries are still placed in the ledger as context, but
they do not count as completed coverage for the new query.
## 10. Execution flow
### 10.1 Tool invocation
1. Acquire the context-scoped blackboard.
2. Refresh the local ledger from persistent observations.
3. Give the coordinator the full ledger snapshot.
4. Coordinator requests segment analysis.
### 10.2 Child analysis
1. Resolve a numeric interval from recording metadata.
2. Calculate missing intervals.
3. For every chunk, acquire a lease.
4. Reuse `succeeded`; skip live `running`; execute only `claimed`.
5. Extract/compress/upload and invoke the configured VLM.
6. Persist timeline observations as soon as they are parsed.
7. Persist the complete segment result before returning to the parent.
8. On final failure, mark that exact chunk failed and keep all sibling results.
### 10.3 Parent synthesis
The parent receives cached and newly completed results in the same format. If
some chunks failed, it receives an explicit partial-result marker and failed
intervals. It may answer with qualified confidence or request a targeted retry.
## 11. Retry and degradation policy
The desired production order is:
1. retry transient upload/poll/generation failures with exponential backoff
and jitter;
2. retry the exact chunk without expanding its identity;
3. split a repeatedly failing chunk into smaller children;
4. use the configured fallback video model;
5. fall back to high-frequency keyframes, OCR, and UI hierarchy around known
action timestamps;
6. return partial evidence with machine-readable failed intervals.
The runtime implements this order with structured failure classes, bounded
bisection, configured fallback models, and a primary-model circuit breaker.
## 12. Provider and sampling strategy
Provider context caching is an optimization, not the system of record. ARTEMIS
must remain correct if a provider cache misses or expires.
Default 1 FPS video sampling is supplemented by exact, dense seeks around
DataEngine action timestamps. Quiet intervals remain sparse while taps,
transitions, toasts, and spinners receive a higher sampling budget.
## 13. Concurrency
- SQLite uses WAL mode and short `BEGIN IMMEDIATE` claim transactions.
- The unique segment key prevents duplicate rows.
- A UUID lease owner identifies one execution attempt.
- Leases expire so crashes do not permanently block work.
- Existing API and transcode semaphores still bound local concurrency.
- Conflict cleaning affects an analyzer's presentation ledger; it never
deletes persistent observations written by another analyzer.
## 14. Cleanup and retention
Three artifact classes have different policies:
1. Trimmed/compressed chunks: temporary, deleted after the call.
2. Provider-uploaded files: temporary, deleted best-effort after inference.
3. Blackboard evidence: durable for the trace/session retention period.
Deleting a trace/session removes blackboard rows through DataEngine and
evidence through the session directory lifecycle.
## 15. Observability
Required counters and trace fields:
- requested duration;
- cached duration;
- newly analyzed duration;
- number of claimed, cached, in-progress, succeeded, and failed chunks;
- provider attempts and error class;
- blackboard key and query key;
- partial versus complete outcome;
- evidence paths attached to observations.
No prompt or trace status should report success merely because an error string
was returned as normal text.
## 16. Compatibility and migration
- Public `video_analyzer` and `video_analyzer_pure` arguments do not change.
- Existing in-memory ledger dictionaries remain the presentation format.
- When DataEngine persistence is unavailable, the blackboard falls back to a
context-scoped in-memory store. This preserves tests and embedded usages but
does not promise process-restart recovery.
- Databases are migrated with `CREATE TABLE IF NOT EXISTS`; no destructive
migration is required.
- Existing traces without blackboard rows continue to work and start empty.
## 17. Security and privacy
- Evidence remains local under the trace directory.
- Provider files are deleted best-effort after requests.
- Blackboard rows must not store credentials or entire model prompts.
- Retention follows trace retention.
- Future cross-session or identity memory requires a separate consent and
privacy design; it is outside this scope.
## 18. Testing strategy
### 18.1 Unit tests
- persistence across two blackboard instances using the same SQLite file;
- deterministic observation deduplication;
- interval union and missing-range calculation;
- exact successful segment reuse;
- live lease suppression and expired lease reclamation;
- failed chunk remains retryable;
- evidence is copied to durable storage;
- two `VideoAnalyzer` instances share prior ledger state;
- repeated `exec_spawn_sub_agent` does not invoke child inference again;
- mixed success/failure returns partial output and preserves success.
### 18.2 Integration tests
- analyze overlapping intervals against a fixture recording;
- interrupt after one successful chunk and resume;
- concurrent identical requests result in one provider call;
- active recording resolves open-ended requests to numeric endpoints;
- evidence remains readable after analyzer cleanup.
### 18.3 Device tests
Per ARTEMIS mobile testing rules, end-to-end mobile flows must be explored and
verified on a connected device before production test scripts are finalized.
The refactor's deterministic unit tests do not require a device; live timing,
fast UI transitions, and recording alignment do.
## 19. Rollout
1. **Complete:** SQLite blackboard, sharing, observation persistence, exact
coverage reuse, leases, and tests.
2. **Complete:** failure classification, jitter, bounded bisection, fallback,
and circuit breaking.
3. **Complete:** recording generations, sealed-prefix metadata, and
generation-scoped caches.
4. **Complete:** action-aware sampling and real audio delivery.
5. **Deferred optimization:** provider file/context caching, gated by an
explicit retention policy.
6. **Future accuracy layer:** semantic/event hierarchical retrieval after
production traces provide a representative evaluation corpus.
## 20. Acceptance criteria
- Two analyzer instances in one task see the same ledger.
- Repeating an identical successful interval/query causes zero new child VLM
calls.
- If one of several chunks fails, successful chunks are available to the next
invocation and are not rerun.
- A crashed `running` chunk becomes reclaimable after lease expiry.
- Persistent evidence survives normal analyzer temporary-file cleanup.
- Existing video-analyzer unit tests and new blackboard tests pass.
Additional reliability criteria:
- timeout/media failures recover through bounded recursive subdivision;
- provider-wide failures do not trigger request fan-out;
- primary-model failures select the configured `utils.video_analyzer` fallback;
- the primary circuit opens after a configured consecutive-failure threshold;
- audio analysis is independently resumable and reusable;
- recording generation changes invalidate stale trim-cache identities;
- frames are sampled densely around recorded mobile actions;
- traces include blackboard status, attempts, failure categories, successful
duration, observation count, and circuit state.
## 21. Implemented production architecture
The completed refactor extends the phase-one blackboard with the following
production controls:
1. Failures are normalized as rate limit, provider outage, timeout,
connection, authentication, bad request, media processing, cancellation,
or unknown. The class determines retryability, bisection, and fallback.
2. Timeout, media, oversized, and unknown failures can recursively bisect a
chunk down to configured size/depth bounds. Provider outages, connections,
and rate limits do not bisect because fan-out would amplify load.
3. Coordinator, video child, and audio child use the configured utility-model
fallback. A context-scoped circuit breaker bypasses an unhealthy primary.
4. Recording results expose `video_id`, `generation`, `sealed_until`, and
`source_revision`. Trim caches are scoped by video UUID and generation;
open-ended requests are resolved to numeric safe ends.
5. Universal video analysis receives sparse baseline frames, dense frames
around DataEngine mobile-action timestamps, and the real audio track.
Audio-only analysis sends a standard base64 audio content block. Models
that reject audio degrade only that video chunk to visual-only analysis.
6. Audio uses the same lease, exact reuse, completion, and failure state
machine as video.
7. DataEngine session deletion removes blackboard rows by session/video key;
evidence is deleted with the trace directory. Universal-path temporary
artifacts are cleaned on early exit.
The persistence schema adds `error_category`, `model_name`, and
`source_generation` to every segment attempt. Migrations are additive and
safe for existing SQLite traces.
## 22. State-of-the-art review and adoption decision
The relevant frontier is not “send the full video to a bigger model.” Recent
systems converge on four architectural ideas:
1. **Agentic coarse-to-fine localization.** [VideoAgent](https://arxiv.org/abs/2403.10517)
iteratively retrieves a small number of frames; [VideoTree](https://arxiv.org/abs/2405.19209)
builds a query-adaptive temporal hierarchy.
2. **Persistent hierarchical multimodal memory.** The memory-augmented
[VideoAgent](https://arxiv.org/abs/2403.11481) separates memory construction
and query-time tool use. [VideoARM](https://arxiv.org/abs/2512.12360) uses an
observe-think-act-memorize loop over hierarchical memory.
3. **Adaptive redundancy reduction.** [LongVU](https://arxiv.org/abs/2410.17434)
removes redundant frames and preserves query-relevant temporal/spatial
detail instead of sampling uniformly.
4. **Retrieval over very long media.** [VideoRAG](https://arxiv.org/abs/2502.01549)
combines graph/text grounding with multimodal retrieval. This is useful for
many-hour corpora, but heavier than one mobile-test recording.
Provider guidance supports the same separation: Gemini's
[video-understanding documentation](https://ai.google.dev/gemini-api/docs/video-understanding)
describes direct audio/video processing and reusable Files API inputs, while
[context caching](https://ai.google.dev/gemini-api/docs/caching) is an
optimization for repeated common input. Neither is a durable work ledger.
### 22.1 Adopted directly
- VideoARM/VideoAgent's observe → reason → act → memorize loop;
- query-scoped coarse-to-fine temporal analysis;
- separation of objective observations and answered query spans;
- adaptive sampling, with mobile action timestamps as the domain-specific
relevance signal;
- independent visual/audio tools and evidence-grounded synthesis.
### 22.2 Not copied wholesale
The research implementations assume offline benchmark videos, often require
GPU feature extractors, and optimize multiple-choice VideoQA. ARTEMIS operates
on a growing recorder stream, must survive provider/process failures, prevent
duplicate paid calls, and tie evidence to test-relative action time. Importing
VideoARM or VideoRAG would add a second orchestration runtime without solving
leases, idempotent commit, active-recording identity, retention, or mobile
alignment.
ARTEMIS therefore ports their architectural invariants, not their
benchmark-specific code, and supplies the production controls the prototypes
do not provide.
## 23. Runtime configuration
All controls live under `video_analyzer` and flow through the SDK builder:
| Setting | Default | Purpose |
| --- | ---: | --- |
| `chunk_size_seconds` | 60 | Initial coarse chunk size |
| `min_chunk_seconds` | 4 | Smallest bisection leaf |
| `max_split_depth` | 4 | Bound failure-driven fan-out |
| `circuit_breaker_threshold` | 3 | Failures before primary circuit opens |
| `circuit_breaker_cooldown_seconds` | 60 | Half-open delay |
| `action_window_seconds` | 2 | Dense window on either side of an action |
| `dense_action_fps` | 4 | Sampling rate in action windows |
| `max_dense_action_frames` | 24 | Dense-frame budget per chunk |
| `native_max_retries` | 1 | Native-provider retries before universal fallback |
| `model_call_timeout_seconds` | 120 | Hard bound for one model response |
The configured `llm_config.utils.video_analyzer.fallback` supplies the model
fallback. Public video tool signatures remain unchanged.
## 24. Verification status
Local verification covers persistence, exact reuse, leases, partial commit,
structured failures, circuit breaking, fallback selection, timeout bisection,
audio reuse, real audio content blocks, action-aware sampling, exact frame
seeking on an MP4 fixture, generation-scoped caches, configuration
propagation, and existing analyzer/controller behavior.
### 24.1 Real-device acceptance (2026-08-25)
A connected Pixel 10 (`59260DLCR00360`) completed a deterministic Google
Calculator recording with independently observed UI ground truth:
- `12+34=46` at 21.15s;
- `7×8=56` at 32.44s;
- history opened at 39.01s and closed at 42.12s;
- the final screen returned to result `56`.
Three query-independent video analyses all matched that ground truth. Each
query was then replayed twice with the identical interval and query. All six
replays returned `CACHED VIDEO ANALYSIS` in roughly 3ms, with no new child
analysis. Final blackboard state was three succeeded segments, 127.8 covered
query-seconds, and eight timestamped observations. The machine-readable
report and retained MP4 are produced by
`scripts/real_device_video_acceptance.py`.
The run also exercised real provider degradation: native Gemini returned a
503 and later stalled a stream. The affected query preserved prior successes,
retried only its own uncovered work, then completed through the configured
universal fallback. Based on that trace, native attempts now default to two
total calls with a 120-second response bound before fallback.
Device exploration also exposed two non-video runtime faults that affect
perceived stability and were fixed as part of the gate:
1. UIAutomator may return current string/dictionary bounds with a stale cached
center. Dynamic taps now always derive their center from fresh bounds and
use the cached center only when bounds are unavailable.
2. A stale desktop IPC port previously blocked every DataEngine event for one
second. IPC connects now use a short localhost timeout plus exponential
backoff, and detached agent initialization has a 30-second hard bound.
The acceptance result demonstrates 100% accuracy and reuse for this defined
fixture and run. It is not a mathematical guarantee for every future app,
video, device, or provider outage; production SLOs require a larger repeated
corpus and ongoing monitoring.