@openscout/protocol 0.2.84 → 0.2.85
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/agent-identity.d.ts.map +1 -1
- package/dist/agent-identity.js +2 -1
- package/dist/events.d.ts +29 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +16 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/observed-status.d.ts +17 -0
- package/dist/observed-status.d.ts.map +1 -1
- package/dist/presence.d.ts +125 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +70 -0
- package/dist/runtime-execution.d.ts +1 -0
- package/dist/runtime-execution.d.ts.map +1 -1
- package/dist/runtime-execution.js +18 -5
- package/dist/runtime-profiles.d.ts +1 -1
- package/dist/runtime-profiles.d.ts.map +1 -1
- package/dist/runtime-profiles.js +2 -0
- package/dist/terminal-host-topology.d.ts +11 -2
- package/dist/terminal-host-topology.d.ts.map +1 -1
- package/dist/terminal-host-topology.js +5 -2
- package/package.json +4 -4
- package/src/agent-identity.ts +2 -1
- package/src/events.ts +37 -1
- package/src/index.ts +1 -0
- package/src/observed-status.ts +17 -0
- package/src/presence.ts +160 -0
- package/src/runtime-execution.ts +18 -5
- package/src/runtime-profiles.ts +2 -0
- package/src/terminal-host-topology.ts +11 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-identity.d.ts","sourceRoot":"","sources":["../src/agent-identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5F,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAsBD,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED,eAAO,MAAM,6BAA6B,sCAAgC,CAAC;AAE3E,eAAO,MAAM,yBAAyB,UAAU,CAAC;AACjD,eAAO,MAAM,8BAA8B,cAAc,CAAC;AAE1D,eAAO,MAAM,6BAA6B,EAAE,WAAW,CAAC,MAAM,CAK5D,CAAC;AAEH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGpF;AAMD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAGrF;
|
|
1
|
+
{"version":3,"file":"agent-identity.d.ts","sourceRoot":"","sources":["../src/agent-identity.ts"],"names":[],"mappings":"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"}
|
package/dist/agent-identity.js
CHANGED
|
@@ -55,7 +55,8 @@ function canonicalizeIdentity(input) {
|
|
|
55
55
|
? normalizeAgentIdentitySegment(input.workspaceQualifier)
|
|
56
56
|
: undefined;
|
|
57
57
|
const profile = input.profile ? normalizeAgentIdentitySegment(input.profile) : undefined;
|
|
58
|
-
const
|
|
58
|
+
const rawHarness = input.harness ? normalizeAgentIdentitySegment(input.harness) : undefined;
|
|
59
|
+
const harness = rawHarness === "oc" ? "opencode" : rawHarness;
|
|
59
60
|
const model = input.model ? normalizeAgentIdentitySegment(input.model) : undefined;
|
|
60
61
|
const nodeQualifier = input.nodeQualifier
|
|
61
62
|
? normalizeAgentIdentitySegment(input.nodeQualifier)
|
package/dist/events.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ import type { ConversationReadCursor } from "./read-receipts.js";
|
|
|
8
8
|
import type { AgentDefinition, AgentEndpoint, ActorIdentity } from "./actors.js";
|
|
9
9
|
import type { CollaborationEvent, CollaborationRecord } from "./collaboration.js";
|
|
10
10
|
import type { ScoutDispatchRecord } from "./scout-dispatch.js";
|
|
11
|
+
import type { PresenceBeat } from "./presence.js";
|
|
12
|
+
import type { ObservedActivity } from "./observed-status.js";
|
|
11
13
|
export declare const OPENSCOUT_CONTROL_EVENT_VERSION: 1;
|
|
12
14
|
export interface ControlEventBase<K extends string, P> {
|
|
13
15
|
id: ScoutId;
|
|
@@ -76,7 +78,33 @@ export type CollaborationEventAppendedEvent = ControlEventBase<"collaboration.ev
|
|
|
76
78
|
export type ScoutDispatchedEvent = ControlEventBase<"scout.dispatched", {
|
|
77
79
|
dispatch: ScoutDispatchRecord;
|
|
78
80
|
}>;
|
|
79
|
-
|
|
81
|
+
/**
|
|
82
|
+
* An agent entered a new activity.
|
|
83
|
+
*
|
|
84
|
+
* Emitted on **transition only** — heartbeats bump the broker's presence map in
|
|
85
|
+
* place and put nothing on the wire. This event is ephemeral by construction:
|
|
86
|
+
* it must never be persisted and must never enter the shared control-event
|
|
87
|
+
* backlog (see {@link isEphemeralControlEvent}). The presence map *is* its
|
|
88
|
+
* backlog — latest-per-agent — and subscribers receive that map on connect.
|
|
89
|
+
*/
|
|
90
|
+
export type PresenceUpdatedEvent = ControlEventBase<"presence.updated", {
|
|
91
|
+
beat: PresenceBeat;
|
|
92
|
+
/** Absent when the agent had no prior presence entry. */
|
|
93
|
+
previousActivity?: ObservedActivity;
|
|
94
|
+
}>;
|
|
95
|
+
export type ControlEvent = NodeUpsertedEvent | ActorRegisteredEvent | AgentRegisteredEvent | AgentEndpointUpsertedEvent | AgentEndpointDeletedEvent | ConversationUpsertedEvent | BindingUpsertedEvent | MessagePostedEvent | ConversationReadCursorUpdatedEvent | InvocationRequestedEvent | FlightUpdatedEvent | DeliveryPlannedEvent | DeliveryAttemptedEvent | DeliveryStateChangedEvent | CollaborationUpsertedEvent | CollaborationEventAppendedEvent | ScoutDispatchedEvent | PresenceUpdatedEvent;
|
|
96
|
+
/**
|
|
97
|
+
* Control-event kinds that are ephemeral by construction.
|
|
98
|
+
*
|
|
99
|
+
* Ephemeral events ride the in-memory control bus for live fan-out and are
|
|
100
|
+
* dropped everywhere else: no SQLite row, no journal entry, no place in the
|
|
101
|
+
* shared bounded backlog. Presence traffic creating zero durable records is a
|
|
102
|
+
* hard constraint, so the durable and backlog paths check this set rather than
|
|
103
|
+
* trusting every call site to route correctly.
|
|
104
|
+
*/
|
|
105
|
+
export declare const EPHEMERAL_CONTROL_EVENT_KINDS: ReadonlySet<ControlEvent["kind"]>;
|
|
106
|
+
/** True when the event must never be persisted or backlogged. */
|
|
107
|
+
export declare function isEphemeralControlEvent(event: Pick<ControlEvent, "kind">): boolean;
|
|
80
108
|
/**
|
|
81
109
|
* Stamp the current envelope version onto a control event when it is missing.
|
|
82
110
|
*
|
package/dist/events.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/dist/events.js
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
export const OPENSCOUT_CONTROL_EVENT_VERSION = 1;
|
|
2
|
+
/**
|
|
3
|
+
* Control-event kinds that are ephemeral by construction.
|
|
4
|
+
*
|
|
5
|
+
* Ephemeral events ride the in-memory control bus for live fan-out and are
|
|
6
|
+
* dropped everywhere else: no SQLite row, no journal entry, no place in the
|
|
7
|
+
* shared bounded backlog. Presence traffic creating zero durable records is a
|
|
8
|
+
* hard constraint, so the durable and backlog paths check this set rather than
|
|
9
|
+
* trusting every call site to route correctly.
|
|
10
|
+
*/
|
|
11
|
+
export const EPHEMERAL_CONTROL_EVENT_KINDS = new Set([
|
|
12
|
+
"presence.updated",
|
|
13
|
+
]);
|
|
14
|
+
/** True when the event must never be persisted or backlogged. */
|
|
15
|
+
export function isEphemeralControlEvent(event) {
|
|
16
|
+
return EPHEMERAL_CONTROL_EVENT_KINDS.has(event.kind);
|
|
17
|
+
}
|
|
2
18
|
/**
|
|
3
19
|
* Stamp the current envelope version onto a control event when it is missing.
|
|
4
20
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from "./budget.js";
|
|
|
20
20
|
export * from "./agent-broker-feed.js";
|
|
21
21
|
export * from "./durable-actions.js";
|
|
22
22
|
export * from "./observed-status.js";
|
|
23
|
+
export * from "./presence.js";
|
|
23
24
|
export * from "./activity.js";
|
|
24
25
|
export * from "./harness-feature-support.js";
|
|
25
26
|
export * from "./host-integrations.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,UAAU,CAAC;AACzB,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,UAAU,CAAC;AACzB,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ export * from "./budget.js";
|
|
|
20
20
|
export * from "./agent-broker-feed.js";
|
|
21
21
|
export * from "./durable-actions.js";
|
|
22
22
|
export * from "./observed-status.js";
|
|
23
|
+
export * from "./presence.js";
|
|
23
24
|
export * from "./activity.js";
|
|
24
25
|
export * from "./harness-feature-support.js";
|
|
25
26
|
export * from "./host-integrations.js";
|
|
@@ -26,8 +26,25 @@ export interface ObservedStatusProjection {
|
|
|
26
26
|
detail?: ObservedStatusDetail;
|
|
27
27
|
provenance: StatusProjectionProvenance[];
|
|
28
28
|
confidence: number;
|
|
29
|
+
/** Last observation. Refreshes on every sample, including no-op samples. */
|
|
29
30
|
updatedAt: number;
|
|
30
31
|
staleAt?: number;
|
|
32
|
+
/**
|
|
33
|
+
* When the *current* {@link ObservedActivity} began — state-entry time, not
|
|
34
|
+
* last-observation time.
|
|
35
|
+
*
|
|
36
|
+
* `updatedAt` answers "how fresh is this claim"; `transitionAt` answers "how
|
|
37
|
+
* long has it been true". Both are needed and they are not interchangeable:
|
|
38
|
+
* an agent heartbeating every 15s while stuck in `executing` for nine minutes
|
|
39
|
+
* has a constantly-moving `updatedAt` and a nine-minute-old `transitionAt`,
|
|
40
|
+
* and the second number is the one an operator acts on.
|
|
41
|
+
*
|
|
42
|
+
* Optional because a single snapshot cannot recover it: activity history is
|
|
43
|
+
* state, so only a projection given a transition log (see the runtime's
|
|
44
|
+
* `ActivityTransitionTracker`) can populate this. Pure snapshot projections
|
|
45
|
+
* leave it undefined rather than guessing.
|
|
46
|
+
*/
|
|
47
|
+
transitionAt?: number;
|
|
31
48
|
}
|
|
32
49
|
export declare function observedStatusDisplay(status: Pick<ObservedStatusProjection, "phase" | "activity">): string;
|
|
33
50
|
//# sourceMappingURL=observed-status.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observed-status.d.ts","sourceRoot":"","sources":["../src/observed-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,MAAM,mBAAmB,GAC3B,cAAc,GACd,YAAY,GACZ,UAAU,GACV,YAAY,GACZ,SAAS,GACT,UAAU,GACV,SAAS,GACT,QAAQ,GACR,OAAO,GACP,SAAS,CAAC;AAEd,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,WAAW,GACX,SAAS,GACT,mBAAmB,GACnB,kBAAkB,GAClB,SAAS,GACT,QAAQ,GACR,WAAW,GACX,QAAQ,GACR,WAAW,GACX,SAAS,GACT,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,MAAM,yBAAyB,GACjC,OAAO,GACP,UAAU,GACV,QAAQ,GACR,KAAK,GACL,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,cAAc,CAAC;AAEnB,MAAM,MAAM,8BAA8B,GACtC,eAAe,GACf,UAAU,GACV,QAAQ,GACR,WAAW,GACX,sBAAsB,GACtB,eAAe,GACf,iBAAiB,GACjB,YAAY,GACZ,SAAS,GACT,MAAM,GACN,qBAAqB,CAAC;AAE1B,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,8BAA8B,CAAC;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,yBAAyB,CAAC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,UAAU,EAAE,0BAA0B,EAAE,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"observed-status.d.ts","sourceRoot":"","sources":["../src/observed-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAExD,MAAM,MAAM,mBAAmB,GAC3B,cAAc,GACd,YAAY,GACZ,UAAU,GACV,YAAY,GACZ,SAAS,GACT,UAAU,GACV,SAAS,GACT,QAAQ,GACR,OAAO,GACP,SAAS,CAAC;AAEd,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,UAAU,GACV,WAAW,GACX,SAAS,GACT,mBAAmB,GACnB,kBAAkB,GAClB,SAAS,GACT,QAAQ,GACR,WAAW,GACX,QAAQ,GACR,WAAW,GACX,SAAS,GACT,SAAS,GACT,SAAS,CAAC;AAEd,MAAM,MAAM,yBAAyB,GACjC,OAAO,GACP,UAAU,GACV,QAAQ,GACR,KAAK,GACL,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,cAAc,CAAC;AAEnB,MAAM,MAAM,8BAA8B,GACtC,eAAe,GACf,UAAU,GACV,QAAQ,GACR,WAAW,GACX,sBAAsB,GACtB,eAAe,GACf,iBAAiB,GACjB,YAAY,GACZ,SAAS,GACT,MAAM,GACN,qBAAqB,CAAC;AAE1B,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,8BAA8B,CAAC;IACvC,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,yBAAyB,CAAC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,UAAU,EAAE,0BAA0B,EAAE,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;;;OAcG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,IAAI,CAAC,wBAAwB,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG,MAAM,CAK1G"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { ScoutId } from "./common.js";
|
|
2
|
+
import type { ObservedActivity, ObservedStatusPhase } from "./observed-status.js";
|
|
3
|
+
/**
|
|
4
|
+
* Agent presence — the shared staleness primitive behind chat presence and the
|
|
5
|
+
* spatial fleet surface.
|
|
6
|
+
*
|
|
7
|
+
* The framing that makes both surfaces work from one implementation: presence
|
|
8
|
+
* is not a pulse, it is a *timestamped fact*.
|
|
9
|
+
*
|
|
10
|
+
* "Agent A has been in activity S, about D, since `transitionAt` — this claim
|
|
11
|
+
* is fresh until `staleAt`."
|
|
12
|
+
*
|
|
13
|
+
* A pulse has to keep arriving to stay true. A timestamped fact keeps rendering
|
|
14
|
+
* live without another byte on the wire, because every renderer derives the
|
|
15
|
+
* changing part (age, decay) from the static payload. That is why decay is
|
|
16
|
+
* never signalled: see {@link presenceLifecycle}.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* How long a beat stays fresh after its last observation.
|
|
20
|
+
*
|
|
21
|
+
* Sized at three missed observations on the ~15s broker cadence: one dropped
|
|
22
|
+
* beat must never flap an agent out of freshness.
|
|
23
|
+
*/
|
|
24
|
+
export declare const PRESENCE_STALE_AFTER_MS = 45000;
|
|
25
|
+
/**
|
|
26
|
+
* How long a stale beat lingers before it is dropped entirely.
|
|
27
|
+
*
|
|
28
|
+
* This window is load-bearing, not a grace period. "The observer went quiet —
|
|
29
|
+
* busy in a long tool call, or dead, cannot yet tell" is a real state, and
|
|
30
|
+
* dropping cleanly at first expiry would erase exactly the ambiguity the
|
|
31
|
+
* operator needs to see.
|
|
32
|
+
*/
|
|
33
|
+
export declare const PRESENCE_GONE_AFTER_STALE_MS = 60000;
|
|
34
|
+
/**
|
|
35
|
+
* Transport freshness of a beat. Derived from timestamps, never transmitted.
|
|
36
|
+
*
|
|
37
|
+
* IMPORTANT — this is not the agent's activity, and the two must never be
|
|
38
|
+
* conflated. `stale` means *no beats are arriving*: the observer went quiet.
|
|
39
|
+
* `activity === "stalled"` means beats **are** arriving and inference says the
|
|
40
|
+
* agent is stuck. They carry opposite information and must render oppositely:
|
|
41
|
+
* stalled is loud and fresh, stale is faded and dated.
|
|
42
|
+
*/
|
|
43
|
+
export type PresenceLifecycle = "fresh" | "stale" | "gone";
|
|
44
|
+
/**
|
|
45
|
+
* One agent's current presence. Keyed per agent, never per (agent × room):
|
|
46
|
+
* the activity is a fact about the agent's single runtime, so a
|
|
47
|
+
* per-conversation "what am I doing in *this* room" would be fiction for any
|
|
48
|
+
* agent doing one thing at a time. Rooms filter and gate this one entry.
|
|
49
|
+
*/
|
|
50
|
+
export interface PresenceBeat {
|
|
51
|
+
agentId: ScoutId;
|
|
52
|
+
displayName?: string;
|
|
53
|
+
/** Existing 16-value vocabulary, verbatim — presence adds no second enum. */
|
|
54
|
+
activity: ObservedActivity;
|
|
55
|
+
/** Carried for non-running edge rendering (error, stopped, unconfigured…). */
|
|
56
|
+
phase: ObservedStatusPhase;
|
|
57
|
+
/** `ObservedStatusDetail.title` — room-gated by `conversationBound`. */
|
|
58
|
+
detail?: string;
|
|
59
|
+
/** When the current activity began. The load-bearing timestamp. */
|
|
60
|
+
transitionAt: number;
|
|
61
|
+
/** Last observation. Freshness input only. */
|
|
62
|
+
updatedAt: number;
|
|
63
|
+
/** Decay boundary. Required here even though it is optional upstream. */
|
|
64
|
+
staleAt: number;
|
|
65
|
+
confidence: number;
|
|
66
|
+
/**
|
|
67
|
+
* When waiting: the durable `scout need` record behind this state.
|
|
68
|
+
*
|
|
69
|
+
* Presence is never the carrier of a question — an ephemeral ask is a lost
|
|
70
|
+
* ask. This is a reference to the durable record, so the loud chat chip can
|
|
71
|
+
* link to the actual question. The invariant is directional: every declared
|
|
72
|
+
* ask produces a presence state; not every presence-waiting has a declared
|
|
73
|
+
* ask (a harness can observe a permission prompt with no need record); and no
|
|
74
|
+
* ask ever exists *only* in presence.
|
|
75
|
+
*/
|
|
76
|
+
needRef?: ScoutId;
|
|
77
|
+
/**
|
|
78
|
+
* The conversation the agent's current work is bound to, when it is bound to
|
|
79
|
+
* one.
|
|
80
|
+
*
|
|
81
|
+
* A per-agent beat cannot carry "is this bound to *your* room" as a boolean —
|
|
82
|
+
* one global entry is read by every room at once, so the boolean would have
|
|
83
|
+
* to be true and false simultaneously. It carries the conversation id
|
|
84
|
+
* instead, and each room derives the answer with
|
|
85
|
+
* {@link isPresenceBoundToConversation}: full `activity + detail` when the
|
|
86
|
+
* work is this room's, bare activity otherwise, so the detail string does not
|
|
87
|
+
* announce what the agent is doing elsewhere.
|
|
88
|
+
*/
|
|
89
|
+
boundConversationId?: ScoutId;
|
|
90
|
+
}
|
|
91
|
+
/** A full presence map, as handed to a subscriber on connect. */
|
|
92
|
+
export interface PresenceSnapshot {
|
|
93
|
+
/** When the snapshot was taken — the "as of" for every beat in it. */
|
|
94
|
+
at: number;
|
|
95
|
+
beats: PresenceBeat[];
|
|
96
|
+
}
|
|
97
|
+
export interface PresenceLifecycleOptions {
|
|
98
|
+
/** Override the linger window after `staleAt`. */
|
|
99
|
+
goneAfterStaleMs?: number;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Classify a beat's transport freshness at `now`.
|
|
103
|
+
*
|
|
104
|
+
* Every renderer computes this locally and continuously. The broker never
|
|
105
|
+
* emits a "now stale" event — a presence-expired signal is the
|
|
106
|
+
* indicator-outlives-process bug wearing a different hat, since it can only
|
|
107
|
+
* arrive over the same transport that just went quiet.
|
|
108
|
+
*/
|
|
109
|
+
export declare function presenceLifecycle(beat: Pick<PresenceBeat, "staleAt">, now: number, options?: PresenceLifecycleOptions): PresenceLifecycle;
|
|
110
|
+
/** Age of the current activity — the number an operator actually reads. */
|
|
111
|
+
export declare function presenceAgeMs(beat: Pick<PresenceBeat, "transitionAt">, now: number): number;
|
|
112
|
+
/** How long the claim itself has gone unrefreshed. Only meaningful once stale. */
|
|
113
|
+
export declare function presenceSilenceMs(beat: Pick<PresenceBeat, "updatedAt">, now: number): number;
|
|
114
|
+
/**
|
|
115
|
+
* Whether a room may render this beat's `detail`.
|
|
116
|
+
*
|
|
117
|
+
* Room-gating is a rendering rule over one global map, not a second map: the
|
|
118
|
+
* activity is a fact about the agent's single runtime, and a per-conversation
|
|
119
|
+
* "what am I doing in *this* room" would be fiction for any agent doing one
|
|
120
|
+
* thing at a time.
|
|
121
|
+
*/
|
|
122
|
+
export declare function isPresenceBoundToConversation(beat: Pick<PresenceBeat, "boundConversationId">, conversationId: ScoutId): boolean;
|
|
123
|
+
/** True once the beat has decayed past the stale window and should be dropped. */
|
|
124
|
+
export declare function isPresenceGone(beat: Pick<PresenceBeat, "staleAt">, now: number, options?: PresenceLifecycleOptions): boolean;
|
|
125
|
+
//# sourceMappingURL=presence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../src/presence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAElF;;;;;;;;;;;;;;GAcG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAE9C;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,8EAA8E;IAC9E,KAAK,EAAE,mBAAmB,CAAC;IAC3B,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;OAWG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,YAAY,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,kDAAkD;IAClD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,EACnC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,wBAA6B,GACrC,iBAAiB,CAKnB;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE3F;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,qBAAqB,CAAC,EAC/C,cAAc,EAAE,OAAO,GACtB,OAAO,CAET;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,EACnC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAET"}
|
package/dist/presence.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent presence — the shared staleness primitive behind chat presence and the
|
|
3
|
+
* spatial fleet surface.
|
|
4
|
+
*
|
|
5
|
+
* The framing that makes both surfaces work from one implementation: presence
|
|
6
|
+
* is not a pulse, it is a *timestamped fact*.
|
|
7
|
+
*
|
|
8
|
+
* "Agent A has been in activity S, about D, since `transitionAt` — this claim
|
|
9
|
+
* is fresh until `staleAt`."
|
|
10
|
+
*
|
|
11
|
+
* A pulse has to keep arriving to stay true. A timestamped fact keeps rendering
|
|
12
|
+
* live without another byte on the wire, because every renderer derives the
|
|
13
|
+
* changing part (age, decay) from the static payload. That is why decay is
|
|
14
|
+
* never signalled: see {@link presenceLifecycle}.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* How long a beat stays fresh after its last observation.
|
|
18
|
+
*
|
|
19
|
+
* Sized at three missed observations on the ~15s broker cadence: one dropped
|
|
20
|
+
* beat must never flap an agent out of freshness.
|
|
21
|
+
*/
|
|
22
|
+
export const PRESENCE_STALE_AFTER_MS = 45_000;
|
|
23
|
+
/**
|
|
24
|
+
* How long a stale beat lingers before it is dropped entirely.
|
|
25
|
+
*
|
|
26
|
+
* This window is load-bearing, not a grace period. "The observer went quiet —
|
|
27
|
+
* busy in a long tool call, or dead, cannot yet tell" is a real state, and
|
|
28
|
+
* dropping cleanly at first expiry would erase exactly the ambiguity the
|
|
29
|
+
* operator needs to see.
|
|
30
|
+
*/
|
|
31
|
+
export const PRESENCE_GONE_AFTER_STALE_MS = 60_000;
|
|
32
|
+
/**
|
|
33
|
+
* Classify a beat's transport freshness at `now`.
|
|
34
|
+
*
|
|
35
|
+
* Every renderer computes this locally and continuously. The broker never
|
|
36
|
+
* emits a "now stale" event — a presence-expired signal is the
|
|
37
|
+
* indicator-outlives-process bug wearing a different hat, since it can only
|
|
38
|
+
* arrive over the same transport that just went quiet.
|
|
39
|
+
*/
|
|
40
|
+
export function presenceLifecycle(beat, now, options = {}) {
|
|
41
|
+
if (now < beat.staleAt)
|
|
42
|
+
return "fresh";
|
|
43
|
+
const goneAfterStaleMs = options.goneAfterStaleMs ?? PRESENCE_GONE_AFTER_STALE_MS;
|
|
44
|
+
if (now < beat.staleAt + goneAfterStaleMs)
|
|
45
|
+
return "stale";
|
|
46
|
+
return "gone";
|
|
47
|
+
}
|
|
48
|
+
/** Age of the current activity — the number an operator actually reads. */
|
|
49
|
+
export function presenceAgeMs(beat, now) {
|
|
50
|
+
return Math.max(0, now - beat.transitionAt);
|
|
51
|
+
}
|
|
52
|
+
/** How long the claim itself has gone unrefreshed. Only meaningful once stale. */
|
|
53
|
+
export function presenceSilenceMs(beat, now) {
|
|
54
|
+
return Math.max(0, now - beat.updatedAt);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether a room may render this beat's `detail`.
|
|
58
|
+
*
|
|
59
|
+
* Room-gating is a rendering rule over one global map, not a second map: the
|
|
60
|
+
* activity is a fact about the agent's single runtime, and a per-conversation
|
|
61
|
+
* "what am I doing in *this* room" would be fiction for any agent doing one
|
|
62
|
+
* thing at a time.
|
|
63
|
+
*/
|
|
64
|
+
export function isPresenceBoundToConversation(beat, conversationId) {
|
|
65
|
+
return beat.boundConversationId !== undefined && beat.boundConversationId === conversationId;
|
|
66
|
+
}
|
|
67
|
+
/** True once the beat has decayed past the stale window and should be dropped. */
|
|
68
|
+
export function isPresenceGone(beat, now, options = {}) {
|
|
69
|
+
return presenceLifecycle(beat, now, options) === "gone";
|
|
70
|
+
}
|
|
@@ -139,6 +139,7 @@ export type ScoutRuntimeTupleIssue = {
|
|
|
139
139
|
dimension: "harness" | "model" | "reasoningEffort";
|
|
140
140
|
message: string;
|
|
141
141
|
};
|
|
142
|
+
export declare function normalizeScoutLaunchableHarness(value: string | null | undefined): ScoutLaunchableHarness | null;
|
|
142
143
|
export declare function isScoutLaunchableHarness(value: string | null | undefined): value is ScoutLaunchableHarness;
|
|
143
144
|
export declare function normalizeScoutReasoningEffort(value: string | null | undefined): ScoutReasoningEffort | null;
|
|
144
145
|
export declare function runtimeDimensionResolution(input: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-execution.d.ts","sourceRoot":"","sources":["../src/runtime-execution.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"runtime-execution.d.ts","sourceRoot":"","sources":["../src/runtime-execution.ts"],"names":[],"mappings":"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"}
|
|
@@ -176,7 +176,8 @@ export function parseScoutRuntimeSpec(input) {
|
|
|
176
176
|
error: "runtime must be <harness>[/<model>[/<effort>]]",
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
|
-
const
|
|
179
|
+
const rawHarness = parts[0].trim().toLowerCase();
|
|
180
|
+
const harness = (rawHarness === "oc" ? "opencode" : rawHarness);
|
|
180
181
|
if (!isScoutLaunchableHarness(harness)) {
|
|
181
182
|
return {
|
|
182
183
|
ok: false,
|
|
@@ -213,9 +214,19 @@ export function formatScoutRuntimeSpec(spec) {
|
|
|
213
214
|
.filter((part) => Boolean(part))
|
|
214
215
|
.join("/");
|
|
215
216
|
}
|
|
217
|
+
export function normalizeScoutLaunchableHarness(value) {
|
|
218
|
+
if (!value)
|
|
219
|
+
return null;
|
|
220
|
+
const normalized = value.trim().toLowerCase();
|
|
221
|
+
if (normalized === "oc")
|
|
222
|
+
return "opencode";
|
|
223
|
+
return isScoutLaunchableHarness(normalized) ? normalized : null;
|
|
224
|
+
}
|
|
216
225
|
export function isScoutLaunchableHarness(value) {
|
|
217
|
-
|
|
218
|
-
|
|
226
|
+
if (!value)
|
|
227
|
+
return false;
|
|
228
|
+
const normalized = value.trim().toLowerCase();
|
|
229
|
+
return normalized === "oc" || SCOUT_LAUNCHABLE_HARNESSES.includes(normalized);
|
|
219
230
|
}
|
|
220
231
|
export function normalizeScoutReasoningEffort(value) {
|
|
221
232
|
const normalized = value?.trim().toLowerCase();
|
|
@@ -260,7 +271,8 @@ export function createScoutExecutionResolution(input) {
|
|
|
260
271
|
};
|
|
261
272
|
}
|
|
262
273
|
export function validateScoutRuntimeTuple(input, catalog) {
|
|
263
|
-
const
|
|
274
|
+
const rawHarness = input.harness?.trim().toLowerCase();
|
|
275
|
+
const harness = rawHarness === "oc" ? "opencode" : rawHarness;
|
|
264
276
|
const model = input.model?.trim();
|
|
265
277
|
const effortRaw = input.reasoningEffort?.trim();
|
|
266
278
|
const issues = [];
|
|
@@ -305,7 +317,8 @@ export function validateScoutRuntimeTuple(input, catalog) {
|
|
|
305
317
|
const modelSelectableHarness = harness === "claude"
|
|
306
318
|
|| harness === "codex"
|
|
307
319
|
|| harness === "grok"
|
|
308
|
-
|| harness === "grok-acp"
|
|
320
|
+
|| harness === "grok-acp"
|
|
321
|
+
|| harness === "opencode";
|
|
309
322
|
if (model && harness && !modelSelectableHarness) {
|
|
310
323
|
issues.push({
|
|
311
324
|
code: "unsupported_model_dimension",
|
|
@@ -3,7 +3,7 @@ import { type ScoutReasoningEffort } from "./runtime-execution.js";
|
|
|
3
3
|
* Reserved natural-language profile names. Their execution definitions stay
|
|
4
4
|
* broker-owned; clients use this list only to recognize unambiguous syntax.
|
|
5
5
|
*/
|
|
6
|
-
export declare const SCOUT_RESERVED_RUNTIME_PROFILE_IDS: readonly ["fable", "kimi", "grok", "opus"];
|
|
6
|
+
export declare const SCOUT_RESERVED_RUNTIME_PROFILE_IDS: readonly ["fable", "kimi", "grok", "opus", "oc", "opencode"];
|
|
7
7
|
export type ScoutReservedRuntimeProfileId = (typeof SCOUT_RESERVED_RUNTIME_PROFILE_IDS)[number];
|
|
8
8
|
export declare const SCOUT_RUNTIME_PROFILE_REASONING_EFFORTS: readonly ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
|
|
9
9
|
export type ScoutRuntimeProfileReasoningEffort = ScoutReasoningEffort;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-profiles.d.ts","sourceRoot":"","sources":["../src/runtime-profiles.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,wBAAwB,CAAC;AAEhC;;;GAGG;AACH,eAAO,MAAM,kCAAkC,
|
|
1
|
+
{"version":3,"file":"runtime-profiles.d.ts","sourceRoot":"","sources":["../src/runtime-profiles.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,wBAAwB,CAAC;AAEhC;;;GAGG;AACH,eAAO,MAAM,kCAAkC,8DAOrC,CAAC;AAEX,MAAM,MAAM,6BAA6B,GACvC,CAAC,OAAO,kCAAkC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtD,eAAO,MAAM,uCAAuC,gFAA0B,CAAC;AAE/E,MAAM,MAAM,kCAAkC,GAAG,oBAAoB,CAAC;AAEtE,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,MAAM,GACZ,6BAA6B,GAAG,IAAI,CAGtC;AAED,wBAAgB,sCAAsC,CACpD,KAAK,EAAE,MAAM,GACZ,kCAAkC,GAAG,IAAI,CAE3C"}
|
package/dist/runtime-profiles.js
CHANGED
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
* The server builds this from `herdr --session <n> workspace list`,
|
|
14
14
|
* `tab list`, and `pane list` JSON, plus the per-tab layout geometry from
|
|
15
15
|
* `herdr --session <n> api snapshot`. A session whose server is stopped
|
|
16
|
-
* projects
|
|
17
|
-
*
|
|
16
|
+
* projects from its persisted `session.json` instead — same shape, marked by
|
|
17
|
+
* `running: false` and `savedAt`; geometry, terminal ids, and live agent
|
|
18
|
+
* status are simply absent from a persisted projection. A session with no
|
|
19
|
+
* persisted state projects as `{ running: false, workspaces: [] }` — an
|
|
20
|
+
* ordinary state, not an error.
|
|
18
21
|
*/
|
|
19
22
|
/** Agent state as herdr reports it, never as Scout infers it. */
|
|
20
23
|
export type HerdrAgentStatus = "idle" | "working" | "blocked" | "done" | "unknown";
|
|
@@ -114,6 +117,12 @@ export type HerdrSessionTopology = {
|
|
|
114
117
|
workspaces: HerdrWorkspaceProjection[];
|
|
115
118
|
/** Server wall-clock when the projection was observed. */
|
|
116
119
|
observedAt: number;
|
|
120
|
+
/**
|
|
121
|
+
* When the projection came from the persisted session state (server stopped),
|
|
122
|
+
* the mtime of that state — the session's last known change. Absent when the
|
|
123
|
+
* projection is live.
|
|
124
|
+
*/
|
|
125
|
+
savedAt?: number | null;
|
|
117
126
|
};
|
|
118
127
|
export declare function emptyHerdrSessionTopology(session: string, running: boolean): HerdrSessionTopology;
|
|
119
128
|
//# sourceMappingURL=terminal-host-topology.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-host-topology.d.ts","sourceRoot":"","sources":["../src/terminal-host-topology.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"terminal-host-topology.d.ts","sourceRoot":"","sources":["../src/terminal-host-topology.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
* The server builds this from `herdr --session <n> workspace list`,
|
|
14
14
|
* `tab list`, and `pane list` JSON, plus the per-tab layout geometry from
|
|
15
15
|
* `herdr --session <n> api snapshot`. A session whose server is stopped
|
|
16
|
-
* projects
|
|
17
|
-
*
|
|
16
|
+
* projects from its persisted `session.json` instead — same shape, marked by
|
|
17
|
+
* `running: false` and `savedAt`; geometry, terminal ids, and live agent
|
|
18
|
+
* status are simply absent from a persisted projection. A session with no
|
|
19
|
+
* persisted state projects as `{ running: false, workspaces: [] }` — an
|
|
20
|
+
* ordinary state, not an error.
|
|
18
21
|
*/
|
|
19
22
|
export function emptyHerdrSessionTopology(session, running) {
|
|
20
23
|
return { session, running, workspaces: [], observedAt: Date.now() };
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openscout/protocol",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.85",
|
|
4
4
|
"description": "Typed protocol for the OpenScout local control plane",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"author": "Arach Tchoupani",
|
|
8
|
-
"homepage": "https://github.com/
|
|
8
|
+
"homepage": "https://github.com/arach/openscout/tree/main/packages/protocol#readme",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/
|
|
11
|
+
"url": "git+https://github.com/arach/openscout.git",
|
|
12
12
|
"directory": "packages/protocol"
|
|
13
13
|
},
|
|
14
14
|
"bugs": {
|
|
15
|
-
"url": "https://github.com/
|
|
15
|
+
"url": "https://github.com/arach/openscout/issues"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"openscout",
|
package/src/agent-identity.ts
CHANGED
|
@@ -104,7 +104,8 @@ function canonicalizeIdentity(input: AgentIdentityInput): AgentIdentityInput | n
|
|
|
104
104
|
? normalizeAgentIdentitySegment(input.workspaceQualifier)
|
|
105
105
|
: undefined;
|
|
106
106
|
const profile = input.profile ? normalizeAgentIdentitySegment(input.profile) : undefined;
|
|
107
|
-
const
|
|
107
|
+
const rawHarness = input.harness ? normalizeAgentIdentitySegment(input.harness) : undefined;
|
|
108
|
+
const harness = rawHarness === "oc" ? "opencode" : rawHarness;
|
|
108
109
|
const model = input.model ? normalizeAgentIdentitySegment(input.model) : undefined;
|
|
109
110
|
const nodeQualifier = input.nodeQualifier
|
|
110
111
|
? normalizeAgentIdentitySegment(input.nodeQualifier)
|
package/src/events.ts
CHANGED
|
@@ -8,6 +8,8 @@ import type { ConversationReadCursor } from "./read-receipts.js";
|
|
|
8
8
|
import type { AgentDefinition, AgentEndpoint, ActorIdentity } from "./actors.js";
|
|
9
9
|
import type { CollaborationEvent, CollaborationRecord } from "./collaboration.js";
|
|
10
10
|
import type { ScoutDispatchRecord } from "./scout-dispatch.js";
|
|
11
|
+
import type { PresenceBeat } from "./presence.js";
|
|
12
|
+
import type { ObservedActivity } from "./observed-status.js";
|
|
11
13
|
|
|
12
14
|
export const OPENSCOUT_CONTROL_EVENT_VERSION = 1 as const;
|
|
13
15
|
|
|
@@ -96,6 +98,21 @@ export type ScoutDispatchedEvent = ControlEventBase<"scout.dispatched", {
|
|
|
96
98
|
dispatch: ScoutDispatchRecord;
|
|
97
99
|
}>;
|
|
98
100
|
|
|
101
|
+
/**
|
|
102
|
+
* An agent entered a new activity.
|
|
103
|
+
*
|
|
104
|
+
* Emitted on **transition only** — heartbeats bump the broker's presence map in
|
|
105
|
+
* place and put nothing on the wire. This event is ephemeral by construction:
|
|
106
|
+
* it must never be persisted and must never enter the shared control-event
|
|
107
|
+
* backlog (see {@link isEphemeralControlEvent}). The presence map *is* its
|
|
108
|
+
* backlog — latest-per-agent — and subscribers receive that map on connect.
|
|
109
|
+
*/
|
|
110
|
+
export type PresenceUpdatedEvent = ControlEventBase<"presence.updated", {
|
|
111
|
+
beat: PresenceBeat;
|
|
112
|
+
/** Absent when the agent had no prior presence entry. */
|
|
113
|
+
previousActivity?: ObservedActivity;
|
|
114
|
+
}>;
|
|
115
|
+
|
|
99
116
|
export type ControlEvent =
|
|
100
117
|
| NodeUpsertedEvent
|
|
101
118
|
| ActorRegisteredEvent
|
|
@@ -113,7 +130,26 @@ export type ControlEvent =
|
|
|
113
130
|
| DeliveryStateChangedEvent
|
|
114
131
|
| CollaborationUpsertedEvent
|
|
115
132
|
| CollaborationEventAppendedEvent
|
|
116
|
-
| ScoutDispatchedEvent
|
|
133
|
+
| ScoutDispatchedEvent
|
|
134
|
+
| PresenceUpdatedEvent;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Control-event kinds that are ephemeral by construction.
|
|
138
|
+
*
|
|
139
|
+
* Ephemeral events ride the in-memory control bus for live fan-out and are
|
|
140
|
+
* dropped everywhere else: no SQLite row, no journal entry, no place in the
|
|
141
|
+
* shared bounded backlog. Presence traffic creating zero durable records is a
|
|
142
|
+
* hard constraint, so the durable and backlog paths check this set rather than
|
|
143
|
+
* trusting every call site to route correctly.
|
|
144
|
+
*/
|
|
145
|
+
export const EPHEMERAL_CONTROL_EVENT_KINDS: ReadonlySet<ControlEvent["kind"]> = new Set<ControlEvent["kind"]>([
|
|
146
|
+
"presence.updated",
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
/** True when the event must never be persisted or backlogged. */
|
|
150
|
+
export function isEphemeralControlEvent(event: Pick<ControlEvent, "kind">): boolean {
|
|
151
|
+
return EPHEMERAL_CONTROL_EVENT_KINDS.has(event.kind);
|
|
152
|
+
}
|
|
117
153
|
|
|
118
154
|
/**
|
|
119
155
|
* Stamp the current envelope version onto a control event when it is missing.
|
package/src/index.ts
CHANGED
|
@@ -20,6 +20,7 @@ export * from "./budget.js";
|
|
|
20
20
|
export * from "./agent-broker-feed.js";
|
|
21
21
|
export * from "./durable-actions.js";
|
|
22
22
|
export * from "./observed-status.js";
|
|
23
|
+
export * from "./presence.js";
|
|
23
24
|
export * from "./activity.js";
|
|
24
25
|
export * from "./harness-feature-support.js";
|
|
25
26
|
export * from "./host-integrations.js";
|
package/src/observed-status.ts
CHANGED
|
@@ -78,8 +78,25 @@ export interface ObservedStatusProjection {
|
|
|
78
78
|
detail?: ObservedStatusDetail;
|
|
79
79
|
provenance: StatusProjectionProvenance[];
|
|
80
80
|
confidence: number;
|
|
81
|
+
/** Last observation. Refreshes on every sample, including no-op samples. */
|
|
81
82
|
updatedAt: number;
|
|
82
83
|
staleAt?: number;
|
|
84
|
+
/**
|
|
85
|
+
* When the *current* {@link ObservedActivity} began — state-entry time, not
|
|
86
|
+
* last-observation time.
|
|
87
|
+
*
|
|
88
|
+
* `updatedAt` answers "how fresh is this claim"; `transitionAt` answers "how
|
|
89
|
+
* long has it been true". Both are needed and they are not interchangeable:
|
|
90
|
+
* an agent heartbeating every 15s while stuck in `executing` for nine minutes
|
|
91
|
+
* has a constantly-moving `updatedAt` and a nine-minute-old `transitionAt`,
|
|
92
|
+
* and the second number is the one an operator acts on.
|
|
93
|
+
*
|
|
94
|
+
* Optional because a single snapshot cannot recover it: activity history is
|
|
95
|
+
* state, so only a projection given a transition log (see the runtime's
|
|
96
|
+
* `ActivityTransitionTracker`) can populate this. Pure snapshot projections
|
|
97
|
+
* leave it undefined rather than guessing.
|
|
98
|
+
*/
|
|
99
|
+
transitionAt?: number;
|
|
83
100
|
}
|
|
84
101
|
|
|
85
102
|
export function observedStatusDisplay(status: Pick<ObservedStatusProjection, "phase" | "activity">): string {
|
package/src/presence.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { ScoutId } from "./common.js";
|
|
2
|
+
import type { ObservedActivity, ObservedStatusPhase } from "./observed-status.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Agent presence — the shared staleness primitive behind chat presence and the
|
|
6
|
+
* spatial fleet surface.
|
|
7
|
+
*
|
|
8
|
+
* The framing that makes both surfaces work from one implementation: presence
|
|
9
|
+
* is not a pulse, it is a *timestamped fact*.
|
|
10
|
+
*
|
|
11
|
+
* "Agent A has been in activity S, about D, since `transitionAt` — this claim
|
|
12
|
+
* is fresh until `staleAt`."
|
|
13
|
+
*
|
|
14
|
+
* A pulse has to keep arriving to stay true. A timestamped fact keeps rendering
|
|
15
|
+
* live without another byte on the wire, because every renderer derives the
|
|
16
|
+
* changing part (age, decay) from the static payload. That is why decay is
|
|
17
|
+
* never signalled: see {@link presenceLifecycle}.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* How long a beat stays fresh after its last observation.
|
|
22
|
+
*
|
|
23
|
+
* Sized at three missed observations on the ~15s broker cadence: one dropped
|
|
24
|
+
* beat must never flap an agent out of freshness.
|
|
25
|
+
*/
|
|
26
|
+
export const PRESENCE_STALE_AFTER_MS = 45_000;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* How long a stale beat lingers before it is dropped entirely.
|
|
30
|
+
*
|
|
31
|
+
* This window is load-bearing, not a grace period. "The observer went quiet —
|
|
32
|
+
* busy in a long tool call, or dead, cannot yet tell" is a real state, and
|
|
33
|
+
* dropping cleanly at first expiry would erase exactly the ambiguity the
|
|
34
|
+
* operator needs to see.
|
|
35
|
+
*/
|
|
36
|
+
export const PRESENCE_GONE_AFTER_STALE_MS = 60_000;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Transport freshness of a beat. Derived from timestamps, never transmitted.
|
|
40
|
+
*
|
|
41
|
+
* IMPORTANT — this is not the agent's activity, and the two must never be
|
|
42
|
+
* conflated. `stale` means *no beats are arriving*: the observer went quiet.
|
|
43
|
+
* `activity === "stalled"` means beats **are** arriving and inference says the
|
|
44
|
+
* agent is stuck. They carry opposite information and must render oppositely:
|
|
45
|
+
* stalled is loud and fresh, stale is faded and dated.
|
|
46
|
+
*/
|
|
47
|
+
export type PresenceLifecycle = "fresh" | "stale" | "gone";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* One agent's current presence. Keyed per agent, never per (agent × room):
|
|
51
|
+
* the activity is a fact about the agent's single runtime, so a
|
|
52
|
+
* per-conversation "what am I doing in *this* room" would be fiction for any
|
|
53
|
+
* agent doing one thing at a time. Rooms filter and gate this one entry.
|
|
54
|
+
*/
|
|
55
|
+
export interface PresenceBeat {
|
|
56
|
+
agentId: ScoutId;
|
|
57
|
+
displayName?: string;
|
|
58
|
+
/** Existing 16-value vocabulary, verbatim — presence adds no second enum. */
|
|
59
|
+
activity: ObservedActivity;
|
|
60
|
+
/** Carried for non-running edge rendering (error, stopped, unconfigured…). */
|
|
61
|
+
phase: ObservedStatusPhase;
|
|
62
|
+
/** `ObservedStatusDetail.title` — room-gated by `conversationBound`. */
|
|
63
|
+
detail?: string;
|
|
64
|
+
/** When the current activity began. The load-bearing timestamp. */
|
|
65
|
+
transitionAt: number;
|
|
66
|
+
/** Last observation. Freshness input only. */
|
|
67
|
+
updatedAt: number;
|
|
68
|
+
/** Decay boundary. Required here even though it is optional upstream. */
|
|
69
|
+
staleAt: number;
|
|
70
|
+
confidence: number;
|
|
71
|
+
/**
|
|
72
|
+
* When waiting: the durable `scout need` record behind this state.
|
|
73
|
+
*
|
|
74
|
+
* Presence is never the carrier of a question — an ephemeral ask is a lost
|
|
75
|
+
* ask. This is a reference to the durable record, so the loud chat chip can
|
|
76
|
+
* link to the actual question. The invariant is directional: every declared
|
|
77
|
+
* ask produces a presence state; not every presence-waiting has a declared
|
|
78
|
+
* ask (a harness can observe a permission prompt with no need record); and no
|
|
79
|
+
* ask ever exists *only* in presence.
|
|
80
|
+
*/
|
|
81
|
+
needRef?: ScoutId;
|
|
82
|
+
/**
|
|
83
|
+
* The conversation the agent's current work is bound to, when it is bound to
|
|
84
|
+
* one.
|
|
85
|
+
*
|
|
86
|
+
* A per-agent beat cannot carry "is this bound to *your* room" as a boolean —
|
|
87
|
+
* one global entry is read by every room at once, so the boolean would have
|
|
88
|
+
* to be true and false simultaneously. It carries the conversation id
|
|
89
|
+
* instead, and each room derives the answer with
|
|
90
|
+
* {@link isPresenceBoundToConversation}: full `activity + detail` when the
|
|
91
|
+
* work is this room's, bare activity otherwise, so the detail string does not
|
|
92
|
+
* announce what the agent is doing elsewhere.
|
|
93
|
+
*/
|
|
94
|
+
boundConversationId?: ScoutId;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** A full presence map, as handed to a subscriber on connect. */
|
|
98
|
+
export interface PresenceSnapshot {
|
|
99
|
+
/** When the snapshot was taken — the "as of" for every beat in it. */
|
|
100
|
+
at: number;
|
|
101
|
+
beats: PresenceBeat[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface PresenceLifecycleOptions {
|
|
105
|
+
/** Override the linger window after `staleAt`. */
|
|
106
|
+
goneAfterStaleMs?: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Classify a beat's transport freshness at `now`.
|
|
111
|
+
*
|
|
112
|
+
* Every renderer computes this locally and continuously. The broker never
|
|
113
|
+
* emits a "now stale" event — a presence-expired signal is the
|
|
114
|
+
* indicator-outlives-process bug wearing a different hat, since it can only
|
|
115
|
+
* arrive over the same transport that just went quiet.
|
|
116
|
+
*/
|
|
117
|
+
export function presenceLifecycle(
|
|
118
|
+
beat: Pick<PresenceBeat, "staleAt">,
|
|
119
|
+
now: number,
|
|
120
|
+
options: PresenceLifecycleOptions = {},
|
|
121
|
+
): PresenceLifecycle {
|
|
122
|
+
if (now < beat.staleAt) return "fresh";
|
|
123
|
+
const goneAfterStaleMs = options.goneAfterStaleMs ?? PRESENCE_GONE_AFTER_STALE_MS;
|
|
124
|
+
if (now < beat.staleAt + goneAfterStaleMs) return "stale";
|
|
125
|
+
return "gone";
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Age of the current activity — the number an operator actually reads. */
|
|
129
|
+
export function presenceAgeMs(beat: Pick<PresenceBeat, "transitionAt">, now: number): number {
|
|
130
|
+
return Math.max(0, now - beat.transitionAt);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** How long the claim itself has gone unrefreshed. Only meaningful once stale. */
|
|
134
|
+
export function presenceSilenceMs(beat: Pick<PresenceBeat, "updatedAt">, now: number): number {
|
|
135
|
+
return Math.max(0, now - beat.updatedAt);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Whether a room may render this beat's `detail`.
|
|
140
|
+
*
|
|
141
|
+
* Room-gating is a rendering rule over one global map, not a second map: the
|
|
142
|
+
* activity is a fact about the agent's single runtime, and a per-conversation
|
|
143
|
+
* "what am I doing in *this* room" would be fiction for any agent doing one
|
|
144
|
+
* thing at a time.
|
|
145
|
+
*/
|
|
146
|
+
export function isPresenceBoundToConversation(
|
|
147
|
+
beat: Pick<PresenceBeat, "boundConversationId">,
|
|
148
|
+
conversationId: ScoutId,
|
|
149
|
+
): boolean {
|
|
150
|
+
return beat.boundConversationId !== undefined && beat.boundConversationId === conversationId;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** True once the beat has decayed past the stale window and should be dropped. */
|
|
154
|
+
export function isPresenceGone(
|
|
155
|
+
beat: Pick<PresenceBeat, "staleAt">,
|
|
156
|
+
now: number,
|
|
157
|
+
options: PresenceLifecycleOptions = {},
|
|
158
|
+
): boolean {
|
|
159
|
+
return presenceLifecycle(beat, now, options) === "gone";
|
|
160
|
+
}
|
package/src/runtime-execution.ts
CHANGED
|
@@ -352,7 +352,8 @@ export function parseScoutRuntimeSpec(input: string): ScoutRuntimeSpecParseResul
|
|
|
352
352
|
error: "runtime must be <harness>[/<model>[/<effort>]]",
|
|
353
353
|
};
|
|
354
354
|
}
|
|
355
|
-
const
|
|
355
|
+
const rawHarness = parts[0]!.trim().toLowerCase();
|
|
356
|
+
const harness = (rawHarness === "oc" ? "opencode" : rawHarness) as ScoutLaunchableHarness;
|
|
356
357
|
if (!isScoutLaunchableHarness(harness)) {
|
|
357
358
|
return {
|
|
358
359
|
ok: false,
|
|
@@ -402,9 +403,19 @@ export type ScoutRuntimeTupleIssue = {
|
|
|
402
403
|
message: string;
|
|
403
404
|
};
|
|
404
405
|
|
|
406
|
+
export function normalizeScoutLaunchableHarness(
|
|
407
|
+
value: string | null | undefined,
|
|
408
|
+
): ScoutLaunchableHarness | null {
|
|
409
|
+
if (!value) return null;
|
|
410
|
+
const normalized = value.trim().toLowerCase();
|
|
411
|
+
if (normalized === "oc") return "opencode";
|
|
412
|
+
return isScoutLaunchableHarness(normalized) ? normalized : null;
|
|
413
|
+
}
|
|
414
|
+
|
|
405
415
|
export function isScoutLaunchableHarness(value: string | null | undefined): value is ScoutLaunchableHarness {
|
|
406
|
-
|
|
407
|
-
|
|
416
|
+
if (!value) return false;
|
|
417
|
+
const normalized = value.trim().toLowerCase();
|
|
418
|
+
return normalized === "oc" || SCOUT_LAUNCHABLE_HARNESSES.includes(normalized as ScoutLaunchableHarness);
|
|
408
419
|
}
|
|
409
420
|
|
|
410
421
|
export function normalizeScoutReasoningEffort(
|
|
@@ -472,7 +483,8 @@ export function validateScoutRuntimeTuple(
|
|
|
472
483
|
input: ScoutRuntimeTuple,
|
|
473
484
|
catalog?: Pick<ScoutRuntimeCapabilityCatalog, "models" | "efforts">,
|
|
474
485
|
): ScoutRuntimeTupleIssue[] {
|
|
475
|
-
const
|
|
486
|
+
const rawHarness = input.harness?.trim().toLowerCase();
|
|
487
|
+
const harness = rawHarness === "oc" ? "opencode" : rawHarness;
|
|
476
488
|
const model = input.model?.trim();
|
|
477
489
|
const effortRaw = input.reasoningEffort?.trim();
|
|
478
490
|
const issues: ScoutRuntimeTupleIssue[] = [];
|
|
@@ -523,7 +535,8 @@ export function validateScoutRuntimeTuple(
|
|
|
523
535
|
const modelSelectableHarness = harness === "claude"
|
|
524
536
|
|| harness === "codex"
|
|
525
537
|
|| harness === "grok"
|
|
526
|
-
|| harness === "grok-acp"
|
|
538
|
+
|| harness === "grok-acp"
|
|
539
|
+
|| harness === "opencode";
|
|
527
540
|
if (model && harness && !modelSelectableHarness) {
|
|
528
541
|
issues.push({
|
|
529
542
|
code: "unsupported_model_dimension",
|
package/src/runtime-profiles.ts
CHANGED
|
@@ -13,8 +13,11 @@
|
|
|
13
13
|
* The server builds this from `herdr --session <n> workspace list`,
|
|
14
14
|
* `tab list`, and `pane list` JSON, plus the per-tab layout geometry from
|
|
15
15
|
* `herdr --session <n> api snapshot`. A session whose server is stopped
|
|
16
|
-
* projects
|
|
17
|
-
*
|
|
16
|
+
* projects from its persisted `session.json` instead — same shape, marked by
|
|
17
|
+
* `running: false` and `savedAt`; geometry, terminal ids, and live agent
|
|
18
|
+
* status are simply absent from a persisted projection. A session with no
|
|
19
|
+
* persisted state projects as `{ running: false, workspaces: [] }` — an
|
|
20
|
+
* ordinary state, not an error.
|
|
18
21
|
*/
|
|
19
22
|
|
|
20
23
|
/** Agent state as herdr reports it, never as Scout infers it. */
|
|
@@ -125,6 +128,12 @@ export type HerdrSessionTopology = {
|
|
|
125
128
|
workspaces: HerdrWorkspaceProjection[];
|
|
126
129
|
/** Server wall-clock when the projection was observed. */
|
|
127
130
|
observedAt: number;
|
|
131
|
+
/**
|
|
132
|
+
* When the projection came from the persisted session state (server stopped),
|
|
133
|
+
* the mtime of that state — the session's last known change. Absent when the
|
|
134
|
+
* projection is live.
|
|
135
|
+
*/
|
|
136
|
+
savedAt?: number | null;
|
|
128
137
|
};
|
|
129
138
|
|
|
130
139
|
export function emptyHerdrSessionTopology(session: string, running: boolean): HerdrSessionTopology {
|