@vtxmacro/cli 2026.9.60 → 2026.9.61

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/README.md CHANGED
@@ -95,11 +95,11 @@ with an uncertain outcome are fenced; same-attempt recovery is not supported.
95
95
  An explicitly capable model from a background service listed above can also
96
96
  control Main in **Agent** mode using the same VTX OAuth grant and its own local
97
97
  adapter-specific vendor credential: ChatGPT, Copilot, or Grok login, or a DeepSeek
98
- or Pi provider API key. VTX assigns the running bot but does not send a VTX-authored prompt or set
99
- the analysis cadence. The assigned runtime keeps a durable Agent thread,
100
- chooses when to wake, requests only the assignment-scoped VTX data it needs (or
101
- none), and submits the normal structured decision for VTX to validate and
102
- execute. Review and Screener remain Provider-only.
98
+ or Pi provider API key. VTX assigns the running bot and supplies canonical Agent instructions. The
99
+ assigned runtime keeps a durable thread, requests assignment-scoped data as
100
+ needed, and chooses whether to submit a structured decision. A configured
101
+ observation schedule runs independently of model turns; it never forces HOLD
102
+ or trading JSON. Without a schedule, the model chooses its next wake. Review and Screener remain Provider-only.
103
103
 
104
104
  Before the first Codex login, enable **Device code authorization for Codex** in
105
105
  ChatGPT Security settings. Only enter a device code from a login you initiated,
@@ -167,7 +167,7 @@ vtx inference-host service install --adapter pi --instance pi-1
167
167
 
168
168
  Pi uses the package-owned SDK and exact provider/model identities. The existing
169
169
  Provider / Agent controls apply: Provider receives VTX's prompt and has no
170
- tools; Main Agent keeps an isolated session and only the three VTX tools.
170
+ tools; Main Agent keeps an isolated session and the canonical VTX assignment tools, including schedule control.
171
171
  The initial qualified models use an OpenAI API key; the release embeds VTX's
172
172
  configured exact model IDs and SDK capability mappings. API compatibility alone
173
173
  does not qualify a provider. Ordinary Pi
@@ -321,6 +321,80 @@ schema plus `provenance` with `source: "external_agent"`, a stable
321
321
  `agent-assignment-release` only when intentionally ending the foreground Agent
322
322
  session; normal cadence is recorded with `agent-assignment-heartbeat`.
323
323
 
324
+ For recurring checks in any supported live Agent harness, configure a schedule
325
+ with `agent-schedule-set --json` after claiming the assignment, then loop
326
+ `agent-check-next --wait-seconds 50 --json`. Keep `agent-run` open: it samples
327
+ markets independently of model reasoning, and the check tool handles waiting.
328
+ When `check_ready` returns, review its observation using your existing
329
+ authorized tools. Finish with `agent-check-complete --json` and stdin
330
+ `{"turn_id":"<returned-id>"}`. No HOLD or trading JSON is required. If you
331
+ choose to submit a decision, include that `turn_id` with the existing
332
+ candidate/provenance fields. A `waiting` response means call check-next again;
333
+ `check_pending` means finish the exact unfinished check first. Resolve an
334
+ uncertain decision through decision-status before completing its check.
335
+ This preserves the original harness session and all its authorized tools
336
+ without writing a harness-specific scheduler. It cannot reopen an exited
337
+ harness session; the managed wrapper below supplies unattended process restart.
338
+
339
+ ## Managed Agent cadence and native tools
340
+
341
+ A compatible managed wrapper lets the harness keep its own authorized tools
342
+ while VTX handles observation timing, thread handoff, heartbeats and service
343
+ supervision. The packaged `vtx-managed-codex` binary is the native Codex
344
+ reference wrapper. Other harnesses need a compatible wrapper; ordinary
345
+ foreground support alone does not prove unattended managed invocation.
346
+
347
+ Create a private, current-user-owned local launch file. For example, point Node
348
+ at the installed wrapper JavaScript and the exact local Codex executable:
349
+
350
+ ```json
351
+ {
352
+ "schema_version": "vtx_managed_harness_launch_v1",
353
+ "executable": "/absolute/path/to/node",
354
+ "argv": ["/absolute/path/to/vtx-managed-codex.js", "/absolute/path/to/codex"],
355
+ "workspace": "/absolute/path/to/agent-workspace",
356
+ "recovery_marker": "/absolute/private/path/to/agent-turn.json"
357
+ }
358
+ ```
359
+
360
+ Use native absolute paths on Windows. The file must be private to the current
361
+ user. The wrapper creates a dedicated native thread with the user's local
362
+ configuration and tools; it does not adopt a visible conversation or approve
363
+ interactive permission requests. Launch commands come only from this local
364
+ file. The host never accepts executable paths from an assignment or model.
365
+
366
+ Pass an initial request on stdin, such as
367
+ `{"schedule":{"interval_seconds":60,"objective":"Observe markets; act only when appropriate.","observation":{"capability":"market.snapshot","arguments":{"symbols":["BTC"],"timeframe":"1m"}}}}`.
368
+ This is an example cadence; the server's configured bounds apply. After the
369
+ normal VTX login for this isolated instance, install and start its worker:
370
+
371
+ ```bash
372
+ vtx inference-host service install --adapter codex --instance agent-1 --launch-config /absolute/private/launch.json --model <exact-model-id> --effort <effort> --json < /absolute/private/schedule.json
373
+ ```
374
+
375
+ The existing OS service manager supervises the worker and starts it at login.
376
+ Use the same instance for service status, logs, stop/start and uninstall. The
377
+ foreground alternative is `agent-managed-run` with the same launch/model/effort
378
+ arguments and JSON input; it requires its process to stay open. Neither command
379
+ starts a VTX bot or changes its profile settings. Bind and start the intended
380
+ bot separately through its authorized normal control path.
381
+
382
+ `agent-schedule-read --instance agent-1 --json` inspects the active assignment.
383
+ `agent-schedule-set --instance agent-1 --json` accepts
384
+ `{"schedule":...}` on stdin; `{"schedule":null}` cancels recurring checks
385
+ without stopping the bot or closing positions. The persisted objective and
386
+ revision travel with the assignment. Saved profile trading interval is separate.
387
+ Long model turns may delay review even while observations continue. Sleep,
388
+ outages and stale sources are recorded as gaps, not successful fresh checks.
389
+
390
+ `prompt.variables` discovers every canonical trading prompt variable;
391
+ `prompt.context` reads selected names or all names for one owned profile.
392
+ Disabled indicators are available request-locally without settings changes.
393
+ Values share provider calculations, format instructions and unavailable
394
+ semantics, including future variables. Full ordinary Insights MCP access and
395
+ external tools remain separate authorized harness connections; the inference
396
+ grant does not expand into account-wide mutation permission.
397
+
324
398
  ## Exo foreground trading inference
325
399
 
326
400
  Exo means [exoharness/exo](https://github.com/exoharness/exo). VTX runs a dedicated
@@ -16,6 +16,7 @@ type Input = {
16
16
  provider: 'openai' | 'venice';
17
17
  mode: 'provider' | 'agent'; systemPrompt: string; userPrompt: string;
18
18
  outputSchema: Json; decisionSchema: Json; dataContract: { id: string; input_schema: Json }[];
19
+ toolSpecs: Json[];
19
20
  requestedModel: string; providerModel: string; reasoningEffort: string;
20
21
  nativeReasoningEffort: string | null; maxRounds: number;
21
22
  deadlineAtMs: number;
@@ -155,19 +156,22 @@ const chatRequestMessages = (harness: ExoHarnessModule, events: unknown[]): Mess
155
156
  return messages;
156
157
  };
157
158
 
158
- const toolsFor = (input: Input): Json[] => input.mode === 'provider' ? [] : [
159
- { name: 'vtx_get_data', description: 'Request assignment-scoped VTX data.', parameters: {
160
- // Keep the complete branch contract, while exposing its common fields to
161
- // Chat tool renderers that enumerate only top-level properties.
162
- type: 'object', additionalProperties: false, required: ['capability', 'arguments'],
163
- properties: { capability: { type: 'string', enum: input.dataContract.map((entry) => entry.id) }, arguments: { type: 'object' } },
164
- oneOf: input.dataContract.map((entry) => ({ type: 'object', additionalProperties: false,
165
- required: ['capability', 'arguments'], properties: { capability: { const: entry.id }, arguments: entry.input_schema } })) } },
166
- { name: 'vtx_submit_decision', description: 'Submit a canonical VTX decision.', parameters: {
167
- type: 'object', additionalProperties: false, required: ['candidate'], properties: { candidate: input.decisionSchema } } },
168
- { name: 'vtx_decision_status', description: 'Resolve a VTX decision operation.', parameters: {
169
- type: 'object', additionalProperties: false, required: ['operation_id'], properties: { operation_id: { type: 'string', minLength: 1 } } } },
170
- ];
159
+ const toolsFor = (input: Input): Json[] => input.mode === 'provider' ? [] : input.toolSpecs.map((spec) => {
160
+ const parameters = record(spec.inputSchema);
161
+ // Chat serializers enumerate common top-level fields; preserve the complete
162
+ // canonical branch schema supplied by the authenticated local broker.
163
+ const branches = Array.isArray(parameters.oneOf) ? parameters.oneOf.map(record) : [];
164
+ const branchProperties = branches.map((branch) => record(branch.properties));
165
+ const common = branchProperties.length > 0 ? {
166
+ type: 'object', additionalProperties: false, required: branches[0].required,
167
+ properties: Object.fromEntries(Object.keys(branchProperties[0]).map((key) => [key,
168
+ branchProperties.every((properties) => key in properties)
169
+ ? key === 'capability' ? { type: 'string', enum: branchProperties.map((properties) => record(properties[key]).const) }
170
+ : { type: 'object' } : {},
171
+ ])),
172
+ } : {};
173
+ return { name: spec.name, description: spec.description, parameters: { ...common, ...parameters } };
174
+ });
171
175
 
172
176
  export default {
173
177
  tools: [],