openvisio-agent 0.21.1 → 0.23.0
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.
- package/CHANGELOG.md +19 -0
- package/README.md +25 -2
- package/USER_GUIDE.md +10 -2
- package/package.json +3 -2
- package/scenarios/runtime.scenarios.mjs +6 -11
- package/scenarios/workspace.scenarios.mjs +2 -1
- package/scripts/certify.mjs +11 -11
- package/scripts/smoke-context-search.mjs +33 -0
- package/src/codex-mcp-proxy.mjs +38 -2
- package/src/context-search.mjs +168 -0
- package/src/context-service.mjs +103 -0
- package/src/context-tools.mjs +44 -0
- package/src/embedding-worker.mjs +29 -0
- package/src/events.mjs +7 -1
- package/src/mastra-harness.mjs +23 -18
- package/src/memory.mjs +7 -6
- package/src/opencode-config.mjs +13 -16
- package/src/runtime-control.mjs +50 -0
- package/src/watch.mjs +173 -129
- package/studio/app.mjs +6 -5
- package/studio/guide.html +9 -1
package/studio/app.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The studio displays recorded, visible actions. It never starts work or infers a plan.
|
|
2
2
|
const MAX_EVENTS = 1000;
|
|
3
3
|
const PAGE_SIZE = 40;
|
|
4
|
-
const terminalStatuses = new Set(['completed', 'failed', 'cancelled', 'offline', 'skipped', 'blocked', 'timeout']);
|
|
4
|
+
const terminalStatuses = new Set(['completed', 'failed', 'cancelled', 'offline', 'skipped', 'blocked', 'timeout', 'continued']);
|
|
5
5
|
const text = (value, max = 24000) => value == null ? '' : String(value).slice(0, max);
|
|
6
6
|
const record = value => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
7
7
|
const array = value => Array.isArray(value) ? value : [];
|
|
@@ -17,7 +17,7 @@ export function normalizeStatus(value, fallback = 'observed') {
|
|
|
17
17
|
if (['failed', 'failure', 'error', 'rejected', 'rate_limited'].includes(status)) return 'failed';
|
|
18
18
|
if (['cancelled', 'canceled', 'aborted', 'interrupted'].includes(status)) return 'cancelled';
|
|
19
19
|
if (['offline', 'stopped', 'disconnected', 'exited'].includes(status)) return 'offline';
|
|
20
|
-
if (['skipped', 'recovering', 'idle', 'blocked', 'timeout'].includes(status)) return status;
|
|
20
|
+
if (['skipped', 'recovering', 'idle', 'blocked', 'timeout', 'continued'].includes(status)) return status;
|
|
21
21
|
if (['starting', 'connecting', 'reused'].includes(status)) return 'connecting';
|
|
22
22
|
return fallback;
|
|
23
23
|
}
|
|
@@ -76,7 +76,7 @@ export function deriveModel(input) {
|
|
|
76
76
|
cycle.events.push(event);
|
|
77
77
|
cycle.lastSeen = event.timestamp;
|
|
78
78
|
// Merge only fields that describe the cycle; tool kind/status belong to that tool.
|
|
79
|
-
for (const field of ['model', 'workdir', 'watcherPid', 'ticket', 'thread', 'lane', 'queueMs', 'durationMs', 'reason']) {
|
|
79
|
+
for (const field of ['model', 'workdir', 'watcherPid', 'ticket', 'thread', 'lane', 'queueMs', 'durationMs', 'reason', 'finishedBy']) {
|
|
80
80
|
if (data[field] != null) cycle.data[field] = data[field];
|
|
81
81
|
}
|
|
82
82
|
if (event.type.startsWith('cycle.')) {
|
|
@@ -185,6 +185,7 @@ export function eventTitle(event) {
|
|
|
185
185
|
const titles = {
|
|
186
186
|
'runtime.started': 'Watcher connected', 'runtime.heartbeat': 'Watcher heartbeat', 'runtime.stopped': 'Watcher stopped',
|
|
187
187
|
'cycle.queued': 'Cycle queued', 'cycle.started': 'Cycle started', 'cycle.finished': 'Cycle finished',
|
|
188
|
+
'cycle.continued': 'Continued in coding workspace',
|
|
188
189
|
'cycle.completed': 'Cycle completed', 'cycle.cancelled': 'Cycle cancelled', 'cycle.failed': 'Cycle failed',
|
|
189
190
|
'plan.updated': 'Plan updated', 'output.progress': 'Progress update', 'output.final': 'Final response',
|
|
190
191
|
'process.started': 'Coding runtime starting', 'process.ready': 'Coding runtime ready', 'process.stopped': 'Coding runtime stopped',
|
|
@@ -238,7 +239,7 @@ export function filterModelItems(model, { view = 'activity', selectedAgent = 'al
|
|
|
238
239
|
&& (!query || searchableEvent(event).includes(query)));
|
|
239
240
|
}
|
|
240
241
|
|
|
241
|
-
const statusLabels = { active: 'Active', queued: 'Queued', completed: 'Completed', failed: 'Failed', cancelled: 'Cancelled', offline: 'Offline', observed: 'Recorded', demo: 'Simulated', uninstrumented: 'No activity yet', unknown: 'Unknown', skipped: 'Skipped', recovering: 'Recovering', idle: 'Idle', blocked: 'Blocked', timeout: 'Timed out', connecting: 'Connecting' };
|
|
242
|
+
const statusLabels = { continued: 'Continued in workspace', active: 'Active', queued: 'Queued', completed: 'Completed', failed: 'Failed', cancelled: 'Cancelled', offline: 'Offline', observed: 'Recorded', demo: 'Simulated', uninstrumented: 'No activity yet', unknown: 'Unknown', skipped: 'Skipped', recovering: 'Recovering', idle: 'Idle', blocked: 'Blocked', timeout: 'Timed out', connecting: 'Connecting' };
|
|
242
243
|
const kindIcons = { cycle: 'stack', tool: 'tool', plan: 'list', output: 'message', runtime: 'pulse', process: 'terminal' };
|
|
243
244
|
const shortTime = timestamp => timeValue(timestamp) ? new Date(timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }) : '—';
|
|
244
245
|
const fullTime = timestamp => timeValue(timestamp) ? new Date(timestamp).toLocaleString() : 'Not recorded';
|
|
@@ -677,7 +678,7 @@ function initializeStudio() {
|
|
|
677
678
|
const count = node('span', 'badge fanout-count');
|
|
678
679
|
const dots = node('span', 'agent-dots'); dots.setAttribute('aria-hidden', 'true');
|
|
679
680
|
displayed.forEach((_, index) => dots.append(node('span', `dot agent-color-${index}`)));
|
|
680
|
-
count.append(dots, node('span', '', `${related.filter(item => item.status === 'completed').length}/${related.length}
|
|
681
|
+
count.append(dots, node('span', '', `${related.filter(item => item.status === 'completed').length}/${related.length} turns ended`));
|
|
681
682
|
header.append(title, count);
|
|
682
683
|
const surface = node('div', 'fanout-surface oa-inset');
|
|
683
684
|
const task = node('div', 'fanout-task');
|
package/studio/guide.html
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
<a href="#start">Open Studio</a>
|
|
22
22
|
<a href="#watchers">Show your agents</a>
|
|
23
23
|
<a href="#find-work">Find and inspect work</a>
|
|
24
|
+
<a href="#recall">Tasks and conversation recall</a>
|
|
24
25
|
<a href="#statuses">Understand statuses</a>
|
|
25
26
|
<a href="#controls">Pause and follow</a>
|
|
26
27
|
<a href="#models">Change models</a>
|
|
@@ -71,15 +72,22 @@
|
|
|
71
72
|
<p><strong>No explicit plan recorded</strong> means the provider did not send a plan in the available history. A missing process ID means the provider did not report that operating-system identifier. Neither message alone means the work failed.</p>
|
|
72
73
|
<p>The process summary counts distinct reported process IDs associated with connected watchers. It is not a system-wide process monitor. The demo deliberately shows no real process count.</p>
|
|
73
74
|
</section>
|
|
75
|
+
<section id="recall">
|
|
76
|
+
<h2>Tasks and conversation recall</h2>
|
|
77
|
+
<p>Tell your agent “I have a task for you” or ask it to check its assignments. The agent has a live task lookup, a searchable tool guide, and short skills it can load when helpful. A lookup does not itself claim, start, or complete a task.</p>
|
|
78
|
+
<p>Ask about an earlier decision, such as “What did we decide about credential storage?” The agent can search recorded conversations by meaning and return to the original channel or thread for verification. It searches messages it has observed or fetched, so conversations it has never read may be missing.</p>
|
|
79
|
+
<p>The first semantic search downloads a local embedding model. Keyword search stays available while it loads. Later inference runs on this computer without an embedding API key. The agent chooses what context to retrieve and when to end its turn.</p>
|
|
80
|
+
</section>
|
|
74
81
|
<section id="statuses">
|
|
75
82
|
<h2>Understand statuses</h2>
|
|
76
83
|
<dl>
|
|
77
84
|
<dt>Live</dt><dd>Your browser is connected to the local Studio server. Check each agent’s own status to see whether its watcher is connected.</dd>
|
|
78
85
|
<dt>Queued / Active</dt><dd>Work is waiting to start, or the current watcher has recorded it as running.</dd>
|
|
79
|
-
<dt>Completed</dt><dd>The selected action or
|
|
86
|
+
<dt>Completed</dt><dd>The selected action finished, or the agent ended its turn. Ending a turn does not automatically mark its ticket done. A completed tool is only one step; inspect the cycle’s final response and the ticket for the overall result.</dd>
|
|
80
87
|
<dt>Blocked / Failed / Timed out</dt><dd>Read the cycle’s Outcome and final response, then check the ticket or watcher log for the cause. Studio has no retry or approval button.</dd>
|
|
81
88
|
<dt>Cancelled / Skipped</dt><dd>The work was stopped or did not proceed. These are separate from successful completion.</dd>
|
|
82
89
|
<dt>Idle / Connecting / Recovering</dt><dd>A coding runtime is waiting, connecting, or attempting recovery. These describe the runtime’s last recorded state.</dd>
|
|
90
|
+
<dt>Continued in workspace</dt><dd>The agent requested its coding workspace and carried the same request and context into a work session. Follow that session for the final response.</dd>
|
|
83
91
|
<dt>Offline</dt><dd>The watcher stopped reporting, exited, or was replaced by a newer run. An unfinished cycle’s outcome is unknown; offline does not mean completed or failed.</dd>
|
|
84
92
|
<dt>Simulated</dt><dd>This record belongs to the demonstration. No real agent is working on it.</dd>
|
|
85
93
|
</dl>
|