@intentic/sandbox-contract 1.160.0 → 1.162.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/dist/contracts/agent.contract.d.ts +24 -2
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/ci.contract.d.ts +56 -0
- package/dist/contracts/ci.contract.d.ts.map +1 -0
- package/dist/contracts/ci.contract.js +9 -0
- package/dist/contracts/ci.contract.js.map +1 -0
- package/dist/contracts/settings.contract.d.ts +45 -20
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +2 -2
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/usage.contract.js +2 -2
- package/dist/contracts/usage.contract.js.map +1 -1
- package/dist/events.d.ts +24 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +9 -0
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +125 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +169 -4
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +47 -3
- package/dist/schemas.js.map +1 -1
- package/package.json +2 -2
- package/src/contracts/ci.contract.ts +14 -0
- package/src/contracts/settings.contract.ts +12 -4
- package/src/contracts/usage.contract.ts +2 -2
- package/src/events.ts +43 -5
- package/src/index.ts +3 -0
- package/src/schemas.test.ts +7 -0
- package/src/schemas.ts +162 -14
package/src/schemas.test.ts
CHANGED
|
@@ -20,6 +20,7 @@ test("a payload from a build that predates a toggle parses, with the new toggle
|
|
|
20
20
|
};
|
|
21
21
|
expect(SandboxSettingsSchema.parse(older)).toEqual({
|
|
22
22
|
...older,
|
|
23
|
+
terseHoldout: 0,
|
|
23
24
|
filterBackend: "native",
|
|
24
25
|
systemPromptMode: "intentic",
|
|
25
26
|
systemPrompt: "",
|
|
@@ -27,6 +28,7 @@ test("a payload from a build that predates a toggle parses, with the new toggle
|
|
|
27
28
|
agentRetentionDays: 3,
|
|
28
29
|
autoLand: true,
|
|
29
30
|
autoResumeOnLimit: false,
|
|
31
|
+
resumeAfterOutage: true,
|
|
30
32
|
});
|
|
31
33
|
});
|
|
32
34
|
|
|
@@ -36,6 +38,8 @@ test("an empty object is the full default settings object", () => {
|
|
|
36
38
|
skills: [],
|
|
37
39
|
hashlineEdits: false,
|
|
38
40
|
terseOutput: false,
|
|
41
|
+
// Off: the steer's turn-level control spends the tokens it measures, so measuring is opt-in.
|
|
42
|
+
terseHoldout: 0,
|
|
39
43
|
iqSearch: false,
|
|
40
44
|
outputCleaners: "off",
|
|
41
45
|
outputHoldout: 0,
|
|
@@ -54,6 +58,9 @@ test("an empty object is the full default settings object", () => {
|
|
|
54
58
|
// sandbox's finished work on branches nobody is watching.
|
|
55
59
|
autoLand: true,
|
|
56
60
|
autoResumeOnLimit: false,
|
|
61
|
+
// On, unlike the limit resume beside it: an outage resume spends nothing the dead turn hadn't already
|
|
62
|
+
// committed, and the turns it saves are the unattended ones nobody is watching to restart by hand.
|
|
63
|
+
resumeAfterOutage: true,
|
|
57
64
|
});
|
|
58
65
|
});
|
|
59
66
|
|
package/src/schemas.ts
CHANGED
|
@@ -648,6 +648,14 @@ export const SandboxSettingsSchema = z.object({
|
|
|
648
648
|
skills: z.array(z.string()).default([]),
|
|
649
649
|
hashlineEdits: z.boolean().default(false),
|
|
650
650
|
terseOutput: z.boolean().default(false),
|
|
651
|
+
/* Measurement control for the terse steer, at TURN level — the same trick `outputHoldout` plays over
|
|
652
|
+
* commands, one layer up. A fraction [0,1] of otherwise-eligible turns run WITHOUT the steer and record
|
|
653
|
+
* which arm they ran on (UsageTurn.terse), so the savings report can compare two real populations.
|
|
654
|
+
*
|
|
655
|
+
* It has to be an experiment: unlike a cleaned command, which yields its own raw baseline in the same
|
|
656
|
+
* event, a turn cannot be re-run to see what it would have said unsteered. 0 ⇒ no measurement (every
|
|
657
|
+
* eligible turn is steered), which is the default because the control costs the very tokens it measures. */
|
|
658
|
+
terseHoldout: z.number().min(0).max(1).default(0),
|
|
651
659
|
/* WHICH SYSTEM PROMPT THE AGENT RUNS ON — the base, before anything this turn composes.
|
|
652
660
|
*
|
|
653
661
|
* intentic — Intentic's own prompt, tuned for this harness (intentic-prompt.ts). The default.
|
|
@@ -697,6 +705,16 @@ export const SandboxSettingsSchema = z.object({
|
|
|
697
705
|
// records every limit-hit either way and the chat OFFERS the toggle at the moment it would have helped —
|
|
698
706
|
// enabling it then still resumes the turn that just bounced.
|
|
699
707
|
autoResumeOnLimit: z.boolean().default(false),
|
|
708
|
+
/* When a turn dies because the MODEL PROVIDER was failing (500/502/503, a 529 at capacity, a dropped
|
|
709
|
+
* socket), re-run it on an escalating backoff until it goes through or the attempts are spent.
|
|
710
|
+
*
|
|
711
|
+
* Defaults ON, unlike autoResumeOnLimit, and the difference is not an inconsistency: a spent allowance is
|
|
712
|
+
* the user's own budget, and resuming into a fresh window spends something they may have been saving. An
|
|
713
|
+
* outage resume spends nothing the dead turn had not already committed, resolves in minutes rather than
|
|
714
|
+
* hours, and — the deciding argument — the turns hurt worst by it are the ones with nobody in the room
|
|
715
|
+
* (automation wakes, Discord, webhooks), which no browser-held preference could ever rescue. It is the same
|
|
716
|
+
* reasoning that leaves the auth resume ungated: this is the provider's failure, not the user's decision. */
|
|
717
|
+
resumeAfterOutage: z.boolean().default(true),
|
|
700
718
|
});
|
|
701
719
|
export type SandboxSettings = z.infer<typeof SandboxSettingsSchema>;
|
|
702
720
|
|
|
@@ -710,22 +728,43 @@ export type SandboxSettings = z.infer<typeof SandboxSettingsSchema>;
|
|
|
710
728
|
export const BuiltinPromptTextSchema = z.object({ text: z.string(), version: z.string() });
|
|
711
729
|
export type BuiltinPromptText = z.infer<typeof BuiltinPromptTextSchema>;
|
|
712
730
|
|
|
713
|
-
|
|
714
|
-
|
|
731
|
+
/* ---- savings report: what each token-reduction mechanism actually saved ----
|
|
732
|
+
*
|
|
733
|
+
* TWO FAMILIES, deliberately never one list of bars. They are measured differently, and a chart that ranks
|
|
734
|
+
* them side by side claims a confidence and a denominator that only one of them has:
|
|
735
|
+
*
|
|
736
|
+
* input — shell output the cleaners trimmed before the model ever saw it. Both sides of the comparison come
|
|
737
|
+
* off the SAME command (raw in, emitted out), so the counterfactual is observed rather than
|
|
738
|
+
* estimated: exact, per command, no sample size to argue about.
|
|
739
|
+
* output — the model's own tokens under the terse steer. There is no second run of the same turn to compare
|
|
740
|
+
* against, so the only honest number is an experiment: a turn-level holdout, an n per arm, and a
|
|
741
|
+
* margin. It is absent entirely until both arms are large enough for the delta to mean anything.
|
|
742
|
+
*
|
|
743
|
+
* The two are also in different units of value — a saved tool-output token is saved again on every later
|
|
744
|
+
* request of that conversation, an output token is saved once but costs several times as much — which is the
|
|
745
|
+
* other reason they are separate sections with separate totals rather than one number.
|
|
746
|
+
*/
|
|
747
|
+
|
|
748
|
+
// One mechanism's realized saving, biggest first. `savedTokens` is what THIS stage removed from what reached
|
|
749
|
+
// it in pipeline order — sequential attribution, which is why the stages sum exactly to raw − emitted and can
|
|
750
|
+
// be drawn as one stacked bar. It is NOT "what turning this cleaner off would cost you": the cap downstream
|
|
751
|
+
// would have eaten some of the same lines. `commands` is how many commands the stage ran on. Negative for the
|
|
752
|
+
// `footer` stage, which adds the retrieval pointer back — a cost on the same ledger as what it bought.
|
|
753
|
+
export const SavingsStageSchema = z.object({ id: z.string(), commands: z.number(), savedTokens: z.number() });
|
|
754
|
+
|
|
755
|
+
// Whichever cleaner is ACTUALLY compressing output owns these numbers, so they are read from that backend's
|
|
715
756
|
// own ledger: "native" aggregates historyRoot/logs/filter-stats.jsonl (one row per agent Bash command, written
|
|
716
757
|
// by agent-output-filter), "rtk" reads rtk's own gain ledger. Reading one ledger regardless of backend is how
|
|
717
758
|
// this card went stale: under rtk the native filter is switched off, nothing appends, and the last numbers
|
|
718
759
|
// written — a test run's, as it happened — sat on the card looking live.
|
|
719
|
-
|
|
720
|
-
// `perCleaner` attributes which cleaner ids fired across commands; `holdout` is the measured control (commands
|
|
721
|
-
// the holdout bypassed) vs the cleaned population — a real saved-% rather than an estimate; `gaps` are
|
|
722
|
-
// high-volume commands that matched no cleaner (the next handler to write). All three are native-only: rtk
|
|
723
|
-
// reports totals, not per-command attribution, so they arrive empty under that backend. Empty/zeroed when no
|
|
724
|
-
// commands have run yet.
|
|
725
|
-
export const CleanerSavingsSchema = z.object({
|
|
760
|
+
export const InputSavingsSchema = z.object({
|
|
726
761
|
// Which backend's ledger these numbers came from — shown on the card, because a number without its source
|
|
727
762
|
// cannot be told apart from a stale one. Defaulted for the same daemon-older-than-browser seam as settings.
|
|
728
763
|
source: z.enum(["native", "rtk"]).default("native"),
|
|
764
|
+
// False ⇒ these totals cover the ledger's whole life, not the range the reader selected: `rtk gain` reports
|
|
765
|
+
// no timestamps, so its numbers cannot be windowed and the screen has to say so rather than let a 7-day
|
|
766
|
+
// filter sit above an all-time figure.
|
|
767
|
+
windowed: z.boolean(),
|
|
729
768
|
// When that ledger last recorded a command (epoch ms), so the card can show its age instead of implying
|
|
730
769
|
// freshness it doesn't have. Absent when the ledger has never been written or its age can't be read.
|
|
731
770
|
updatedAt: z.number().optional(),
|
|
@@ -733,11 +772,43 @@ export const CleanerSavingsSchema = z.object({
|
|
|
733
772
|
rawTokens: z.number(),
|
|
734
773
|
emittedTokens: z.number(),
|
|
735
774
|
savedPct: z.number(),
|
|
736
|
-
|
|
775
|
+
// Per-stage attribution, biggest first. Native-only: rtk reports totals, not which of its handlers fired.
|
|
776
|
+
perCleaner: z.array(SavingsStageSchema),
|
|
777
|
+
// The measured control — commands the holdout left raw — against the cleaned population. A real saved-%
|
|
778
|
+
// for the pipeline as a whole rather than an estimate, and the only whole-pipeline counterfactual there is.
|
|
737
779
|
holdout: z.object({ cleaned: z.number(), heldOut: z.number(), measuredSavedPct: z.number().optional() }),
|
|
780
|
+
// High-volume commands that matched no cleaner: where the next handler is worth writing. Native-only.
|
|
738
781
|
gaps: z.array(z.object({ command: z.string(), tokens: z.number() })),
|
|
739
782
|
});
|
|
740
|
-
export type
|
|
783
|
+
export type InputSavings = z.infer<typeof InputSavingsSchema>;
|
|
784
|
+
|
|
785
|
+
// One arm of the turn-level experiment: the turns that ran with the steer, and the turns the holdout ran
|
|
786
|
+
// without it. Mean output tokens PER TURN, because the arms never hold the same number of turns.
|
|
787
|
+
export const SavingsArmSchema = z.object({ turns: z.number(), meanOutputTokens: z.number() });
|
|
788
|
+
|
|
789
|
+
// The terse steer, as measured. Only turns where the steer was ELIGIBLE are counted — a turn under a custom
|
|
790
|
+
// system prompt drops the steer along with everything else the daemon appends, so it belongs to neither arm.
|
|
791
|
+
export const OutputSavingsSchema = z.object({
|
|
792
|
+
on: SavingsArmSchema,
|
|
793
|
+
off: SavingsArmSchema,
|
|
794
|
+
// Turns per arm before a delta is reported at all. Carried on the wire so the screen's "measuring…" state
|
|
795
|
+
// counts toward the daemon's real threshold instead of a number the browser guessed.
|
|
796
|
+
minTurns: z.number(),
|
|
797
|
+
/* The three below are present TOGETHER, and only once both arms clear `minTurns` — a schema that can't
|
|
798
|
+
* express a half-measured experiment is how a 34%-that-becomes-8%-tomorrow never reaches the screen.
|
|
799
|
+
* deltaPct — change in mean output tokens per turn under the steer; negative is a saving.
|
|
800
|
+
* marginPct — ± percentage points, 95% (Welch, unequal variances and unequal arms).
|
|
801
|
+
* savedTokens — what the delta is worth over the turns that actually ran with the steer, in this window. */
|
|
802
|
+
deltaPct: z.number().optional(),
|
|
803
|
+
marginPct: z.number().optional(),
|
|
804
|
+
savedTokens: z.number().optional(),
|
|
805
|
+
});
|
|
806
|
+
export type OutputSavings = z.infer<typeof OutputSavingsSchema>;
|
|
807
|
+
|
|
808
|
+
// `output` is absent when the experiment isn't running at all (terse off, or no holdout set) — a section that
|
|
809
|
+
// isn't there reads as "not measured", which is the truth, while zeros would read as "measured, worth nothing".
|
|
810
|
+
export const SavingsReportSchema = z.object({ input: InputSavingsSchema, output: OutputSavingsSchema.optional() });
|
|
811
|
+
export type SavingsReport = z.infer<typeof SavingsReportSchema>;
|
|
741
812
|
|
|
742
813
|
// ---- intentic CLI ----
|
|
743
814
|
|
|
@@ -1926,6 +1997,73 @@ export type AutomationSummary = z.infer<typeof AutomationSummarySchema>;
|
|
|
1926
1997
|
export const AutomationsListSchema = z.object({ automations: z.array(AutomationSummarySchema) });
|
|
1927
1998
|
export const AutomationIdParamSchema = z.object({ id: z.string() });
|
|
1928
1999
|
|
|
2000
|
+
// ---- ci: pipeline runs on the workspace repos' github/gitlab remotes ----
|
|
2001
|
+
// The daemon maps each workspace repo to the CI project behind its remote (a connected github/gitlab
|
|
2002
|
+
// capability supplies the token), registers a webhook so completed pipelines dispatch `ci` listener
|
|
2003
|
+
// automations instantly, and serves the Pipelines rail view from a webhook-freshened cache backfilled over the
|
|
2004
|
+
// same REST clients. `host` names WHICH provider API serves a repo; the listener provider is always `ci` — one
|
|
2005
|
+
// automation covers both hosts because the repo, not the vendor, is what a trigger narrows to.
|
|
2006
|
+
|
|
2007
|
+
export const CiHostSchema = z.enum(["github", "gitlab"]);
|
|
2008
|
+
export type CiHost = z.infer<typeof CiHostSchema>;
|
|
2009
|
+
|
|
2010
|
+
// Terminal-or-not over both vendors' vocabularies: github's status+conclusion pair and gitlab's single status
|
|
2011
|
+
// both collapse onto these five. `running` covers everything non-terminal (queued, manual, preparing …) — the
|
|
2012
|
+
// view only needs "still moving" vs the three ways it stopped.
|
|
2013
|
+
export const PipelineStatusSchema = z.enum(["running", "success", "failed", "canceled", "skipped"]);
|
|
2014
|
+
export type PipelineStatus = z.infer<typeof PipelineStatusSchema>;
|
|
2015
|
+
|
|
2016
|
+
export const PipelineRunSchema = z.object({
|
|
2017
|
+
// The workspace repo dir (the panels `repo` convention) — the join key back to the tree and to triggers.
|
|
2018
|
+
repo: z.string(),
|
|
2019
|
+
host: CiHostSchema,
|
|
2020
|
+
// owner/name (github) or the full project path (gitlab).
|
|
2021
|
+
project: z.string(),
|
|
2022
|
+
// The vendor's numeric run/pipeline id — what rerun/cancel address.
|
|
2023
|
+
runId: z.number(),
|
|
2024
|
+
// github's display_title (the commit/PR line); gitlab's pipeline name when set. Absent ⇒ the view shows ref@sha.
|
|
2025
|
+
title: z.string().optional(),
|
|
2026
|
+
branch: z.string(),
|
|
2027
|
+
sha: z.string(),
|
|
2028
|
+
status: PipelineStatusSchema,
|
|
2029
|
+
// The vendor's run page — the deep link out.
|
|
2030
|
+
url: z.string(),
|
|
2031
|
+
createdAt: z.number(),
|
|
2032
|
+
durationSeconds: z.number().optional(),
|
|
2033
|
+
// Names of the failed jobs — fetched only for failed runs (one extra call), so a wake or a view names what broke.
|
|
2034
|
+
failedJobs: z.array(z.string()).optional(),
|
|
2035
|
+
});
|
|
2036
|
+
export type PipelineRun = z.infer<typeof PipelineRunSchema>;
|
|
2037
|
+
|
|
2038
|
+
// One mapped repo's CI wiring state. `hookWarning` is the manual-setup story when webhook registration was
|
|
2039
|
+
// refused (token scope, role) or impossible (no public URL): what happened plus the target URL + secret to
|
|
2040
|
+
// paste into the repo's webhook settings — the git-access sshRegistrationWarning pattern.
|
|
2041
|
+
export const CiRepoSchema = z.object({
|
|
2042
|
+
repo: z.string(),
|
|
2043
|
+
host: CiHostSchema,
|
|
2044
|
+
project: z.string(),
|
|
2045
|
+
// The project's home page on its host.
|
|
2046
|
+
url: z.string(),
|
|
2047
|
+
hookWarning: z.string().optional(),
|
|
2048
|
+
});
|
|
2049
|
+
export type CiRepo = z.infer<typeof CiRepoSchema>;
|
|
2050
|
+
|
|
2051
|
+
export const CiRunsResponseSchema = z.object({
|
|
2052
|
+
repos: z.array(CiRepoSchema),
|
|
2053
|
+
// Newest first, across all mapped repos.
|
|
2054
|
+
runs: z.array(PipelineRunSchema),
|
|
2055
|
+
});
|
|
2056
|
+
export type CiRunsResponse = z.infer<typeof CiRunsResponseSchema>;
|
|
2057
|
+
|
|
2058
|
+
// rerun/cancel/fix address a run by repo + vendor id; the daemon re-resolves repo → project + token per call,
|
|
2059
|
+
// so a stale card can't act on a project the workspace no longer maps to.
|
|
2060
|
+
export const CiRunParamSchema = z.object({ repo: z.string(), runId: z.number() });
|
|
2061
|
+
export type CiRunParam = z.infer<typeof CiRunParamSchema>;
|
|
2062
|
+
|
|
2063
|
+
// The fix route opens an isolated conversation (fleet card + chat tab) seeded with the failure context.
|
|
2064
|
+
export const CiFixResponseSchema = z.object({ conversationId: z.string() });
|
|
2065
|
+
export type CiFixResponse = z.infer<typeof CiFixResponseSchema>;
|
|
2066
|
+
|
|
1929
2067
|
// ---- drafts: agent-proposed posts awaiting owner approval (.intentic/drafts/<id>.json) ----
|
|
1930
2068
|
// One JSON file per draft. The AGENT creates drafts with its normal file tools — it can't call daemon routes,
|
|
1931
2069
|
// the same split as the environment proposal — while the daemon edits/deletes them on the owner's behalf, so
|
|
@@ -2260,6 +2398,14 @@ export const UsageTurnSchema = z.object({
|
|
|
2260
2398
|
cacheCreationTokens: z.number(),
|
|
2261
2399
|
costUsd: z.number(),
|
|
2262
2400
|
durationMs: z.number(),
|
|
2401
|
+
/* Which arm of the terse experiment this turn ran on (settings.terseHoldout) — the only record of it, and
|
|
2402
|
+
* the reason the savings report can say what the steer is worth instead of guessing.
|
|
2403
|
+
*
|
|
2404
|
+
* ABSENT means "not part of the experiment", not "off": a turn under a custom system prompt drops the
|
|
2405
|
+
* steer along with everything else the daemon appends, and a turn run with the experiment switched off has
|
|
2406
|
+
* no control to be compared against. Pooling those into the off-arm would compare steered turns against a
|
|
2407
|
+
* population selected by something other than the coin flip, which is not a control at all. */
|
|
2408
|
+
terse: z.boolean().optional(),
|
|
2263
2409
|
});
|
|
2264
2410
|
export type UsageTurn = z.infer<typeof UsageTurnSchema>;
|
|
2265
2411
|
|
|
@@ -2287,12 +2433,14 @@ export const UsageRollupRowSchema = z.object({
|
|
|
2287
2433
|
durationMs: z.number(),
|
|
2288
2434
|
});
|
|
2289
2435
|
export type UsageRollupRow = z.infer<typeof UsageRollupRowSchema>;
|
|
2290
|
-
// Inclusive UTC day bounds (YYYY-MM-DD). Both absent ⇒ the whole ledger.
|
|
2291
|
-
|
|
2436
|
+
// Inclusive UTC day bounds (YYYY-MM-DD). Both absent ⇒ the whole ledger. Shared by every windowed read of a
|
|
2437
|
+
// daemon ledger (spend, savings): one window shape, so a screen that filters two ledgers at once filters them
|
|
2438
|
+
// with the same calendar.
|
|
2439
|
+
export const DayWindowQuerySchema = z.object({
|
|
2292
2440
|
from: z.string().optional(),
|
|
2293
2441
|
to: z.string().optional(),
|
|
2294
2442
|
});
|
|
2295
|
-
export type
|
|
2443
|
+
export type DayWindowQuery = z.infer<typeof DayWindowQuerySchema>;
|
|
2296
2444
|
export const UsageRollupSchema = z.object({ rows: z.array(UsageRollupRowSchema) });
|
|
2297
2445
|
|
|
2298
2446
|
// ---- usage: per-account token/cost totals ----
|