@yanlinglabs/winter-agent-sdk 0.0.1 → 0.0.3
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 +30 -0
- package/dist/index-51ysrfm8.js +614 -0
- package/dist/index-9e98bg1r.js +707 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +292 -741
- package/dist/messaging/adapter.d.ts +119 -0
- package/dist/messaging/addressing.d.ts +13 -0
- package/dist/messaging/attribution.d.ts +43 -0
- package/dist/messaging/idle.d.ts +54 -0
- package/dist/messaging/inbound.d.ts +39 -0
- package/dist/messaging/index.d.ts +15 -0
- package/dist/messaging/index.js +118 -0
- package/dist/messaging/outcomes.d.ts +25 -0
- package/dist/messaging/resolution.d.ts +39 -0
- package/dist/messaging/router.d.ts +100 -0
- package/dist/paths/project-key.d.ts +2 -0
- package/dist/protocol/messaging.d.ts +111 -0
- package/dist/query.d.ts +91 -0
- package/dist/tools/accept.d.ts +39 -0
- package/dist/tools/advisor.d.ts +106 -0
- package/dist/tools/definitions.d.ts +31 -0
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.js +438 -0
- package/dist/tools/messaging-handlers.d.ts +52 -0
- package/dist/tools/port.d.ts +39 -0
- package/dist/tools/schemas.d.ts +48 -0
- package/dist/version.d.ts +1 -0
- package/package.json +13 -5
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { DeliveryOutcome, GlobalAgentMessage, ListedRuntimeObject, NotificationRecord, PermissionClassLabel, RuntimeAddress } from "../messaging/index.js";
|
|
2
|
+
/** Every subtype, in one place, so neither side spells a literal the other does not. */
|
|
3
|
+
export declare const MESSAGING_CONTROL_SUBTYPES: {
|
|
4
|
+
readonly listReachable: "messaging.list_reachable";
|
|
5
|
+
readonly deliver: "messaging.deliver";
|
|
6
|
+
readonly steerChild: "messaging.steer_child";
|
|
7
|
+
readonly resumeChild: "messaging.resume_child";
|
|
8
|
+
readonly subscribeIdle: "messaging.subscribe_idle";
|
|
9
|
+
readonly senderClass: "messaging.sender_class";
|
|
10
|
+
readonly readNotifications: "messaging.read_notifications";
|
|
11
|
+
readonly idleNotice: "messaging.idle_notice";
|
|
12
|
+
};
|
|
13
|
+
export type MessagingControlSubtype = (typeof MESSAGING_CONTROL_SUBTYPES)[keyof typeof MESSAGING_CONTROL_SUBTYPES];
|
|
14
|
+
/**
|
|
15
|
+
* The subtypes the RUNTIME serves (host -> runtime). The engine dispatches on exactly this set.
|
|
16
|
+
*
|
|
17
|
+
* `idleNotice` is deliberately absent: it travels runtime -> host, is answered by the WRAPPER, and a
|
|
18
|
+
* runtime that dispatched it would be answering its own request.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MESSAGING_HOST_REQUEST_SUBTYPES: readonly MessagingControlSubtype[];
|
|
21
|
+
/** The subtypes the WRAPPER serves (runtime -> host). */
|
|
22
|
+
export declare const MESSAGING_RUNTIME_REQUEST_SUBTYPES: readonly MessagingControlSubtype[];
|
|
23
|
+
/** Every subtype, both directions. */
|
|
24
|
+
export declare const MESSAGING_CONTROL_SUBTYPE_LIST: readonly MessagingControlSubtype[];
|
|
25
|
+
/** `messaging.list_reachable` and `messaging.sender_class` are payload-free (like the pinned `list_models`). */
|
|
26
|
+
export interface MessagingDeliverRequest {
|
|
27
|
+
message: GlobalAgentMessage;
|
|
28
|
+
}
|
|
29
|
+
export interface MessagingChildRequest {
|
|
30
|
+
/** A canonical address, or a bare child id read within the receiving session. */
|
|
31
|
+
id: string;
|
|
32
|
+
message: GlobalAgentMessage;
|
|
33
|
+
}
|
|
34
|
+
export interface MessagingSubscribeIdleRequest {
|
|
35
|
+
/** A canonical address, or a bare child id read within the receiving session. */
|
|
36
|
+
id: string;
|
|
37
|
+
/**
|
|
38
|
+
* The HOST's own message id. The facet never allocates one: allocation is the router's
|
|
39
|
+
* (WS-10 §12 keys it to the sender session plus tool-call id), and a second allocator on the far
|
|
40
|
+
* side of a pipe would break the retry idempotency that key exists for.
|
|
41
|
+
*/
|
|
42
|
+
messageId: string;
|
|
43
|
+
/**
|
|
44
|
+
* Whose notification queue an eventual idle notice belongs to. WS-10 §15's `subscribeIdle(addr,
|
|
45
|
+
* {messageId})` carries no subscriber at all, and the in-process reference answers that gap with a
|
|
46
|
+
* router-side directory keyed by messageId -- which a REMOTE caller cannot write into. So the
|
|
47
|
+
* caller names it here; absent means the receiving session itself.
|
|
48
|
+
*/
|
|
49
|
+
subscriberSessionId?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface MessagingSenderClassResponse {
|
|
52
|
+
senderClass: PermissionClassLabel;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `messaging.read_notifications` — the CATCH-UP half of `notify_when_idle` (WS-15 §6.4).
|
|
56
|
+
*
|
|
57
|
+
* A bounded page: `max` caps how many records come back and `remaining` says how many are still
|
|
58
|
+
* queued, so a host recovering after a restart drains in pages rather than in one unbounded frame
|
|
59
|
+
* whose size nothing governs.
|
|
60
|
+
*/
|
|
61
|
+
export interface MessagingReadNotificationsRequest {
|
|
62
|
+
/** Whose queue to drain. Absent = the receiving session's own. */
|
|
63
|
+
subscriberSessionId?: string;
|
|
64
|
+
/** Page size. Absent = everything queued for that key. */
|
|
65
|
+
max?: number;
|
|
66
|
+
}
|
|
67
|
+
export interface MessagingNotificationsPage {
|
|
68
|
+
notifications: NotificationRecord[];
|
|
69
|
+
remaining: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* `messaging.idle_notice` — the LIVE half, and the ONE subtype that travels runtime -> host.
|
|
73
|
+
*
|
|
74
|
+
* The SAME notice the drain returns, carrying the same `notification_id`, because the queue is the
|
|
75
|
+
* durable record and this is a signal derived from it: a host that missed the frame (crashed, not yet
|
|
76
|
+
* connected) still finds the entry via `read_notifications`, and a host that got both dedupes on the
|
|
77
|
+
* id. The runtime does NOT wait for a handler — an unanswered or refused notice is a dropped LIVE
|
|
78
|
+
* signal, never a dropped notice.
|
|
79
|
+
*/
|
|
80
|
+
export interface MessagingIdleNoticePayload {
|
|
81
|
+
/** The queue key the notice was filed under -- the SUBSCRIBER, not the target that went idle. */
|
|
82
|
+
subscriberSessionId: string;
|
|
83
|
+
notice: NotificationRecord;
|
|
84
|
+
}
|
|
85
|
+
export declare function isRuntimeAddress(v: unknown): v is RuntimeAddress;
|
|
86
|
+
export declare function isGlobalAgentMessage(v: unknown): v is GlobalAgentMessage;
|
|
87
|
+
export declare function isDeliveryOutcome(v: unknown): v is DeliveryOutcome;
|
|
88
|
+
export declare function isListedRuntimeObjectArray(v: unknown): v is ListedRuntimeObject[];
|
|
89
|
+
export declare function isPermissionClassLabel(v: unknown): v is PermissionClassLabel;
|
|
90
|
+
export declare function isMessagingDeliverRequest(v: unknown): v is MessagingDeliverRequest;
|
|
91
|
+
export declare function isMessagingChildRequest(v: unknown): v is MessagingChildRequest;
|
|
92
|
+
export declare function isNotificationRecord(v: unknown): v is NotificationRecord;
|
|
93
|
+
export declare function isMessagingNotificationsPage(v: unknown): v is MessagingNotificationsPage;
|
|
94
|
+
export declare function isMessagingIdleNoticePayload(v: unknown): v is MessagingIdleNoticePayload;
|
|
95
|
+
export declare function isMessagingReadNotificationsRequest(v: unknown): v is MessagingReadNotificationsRequest;
|
|
96
|
+
export declare function isMessagingSubscribeIdleRequest(v: unknown): v is MessagingSubscribeIdleRequest;
|
|
97
|
+
/**
|
|
98
|
+
* Turns a facet `id` into a `RuntimeAddress` within the receiving session.
|
|
99
|
+
*
|
|
100
|
+
* TWO forms, and no third:
|
|
101
|
+
* 1. a CANONICAL address (`session:<id>` / `agent:<parent>:<child>`) -- parsed by WS-10 §11's own
|
|
102
|
+
* inverse, so a router that already holds a directory entry addresses it exactly;
|
|
103
|
+
* 2. a bare stable CHILD id -- read within the receiving session, which is the only scope in which
|
|
104
|
+
* a child id means anything (WS-10 §10.3: a child is reachable only through its owning parent).
|
|
105
|
+
*
|
|
106
|
+
* It deliberately does NOT fall back to display-name lookup. That is resolution rule 3, and rules
|
|
107
|
+
* 3/4/5 are inseparable -- a name that resolves here would be a name that never got its ambiguity
|
|
108
|
+
* and staleness checks, because those need the whole directory the router holds and this side does
|
|
109
|
+
* not.
|
|
110
|
+
*/
|
|
111
|
+
export declare function resolveFacetTarget(sessionId: string, id: string, parse: (s: string) => RuntimeAddress | undefined, buildChild: (parent: string, childId: string) => RuntimeAddress): RuntimeAddress;
|
package/dist/query.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { SdkMessage as RuntimeSdkMessage } from "./protocol/frames.js";
|
|
|
2
2
|
import type { AccountInfo, ModelInfo, ModelFamilyListing, RewindFilesResult } from "./protocol/config.js";
|
|
3
3
|
import { type Options } from "./options.js";
|
|
4
4
|
import type { PermissionMode, PermissionResult } from "./permissions/types.js";
|
|
5
|
+
import { type DeliveryOutcome, type GlobalAgentMessage, type ListedRuntimeObject, type PermissionClassLabel } from "./messaging/index.js";
|
|
6
|
+
import { type MessagingNotificationsPage, type MessagingIdleNoticePayload } from "./protocol/messaging.js";
|
|
5
7
|
export type SdkMessage = Extract<RuntimeSdkMessage, {
|
|
6
8
|
type: "system";
|
|
7
9
|
} | {
|
|
@@ -24,6 +26,88 @@ export interface QueryInternal {
|
|
|
24
26
|
registerControlRequestHandler(subtype: string, handler: ControlRequestHandler): void;
|
|
25
27
|
respondPermission(requestId: string, result: PermissionResult): void;
|
|
26
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* R-7b-4: the per-session MESSAGING FACET -- `RuntimeMessagingAdapter` (WS-10 §15) reached over this
|
|
31
|
+
* session's own control channel.
|
|
32
|
+
*
|
|
33
|
+
* WHO CALLS IT: `@yanlinglabs/winter-runtime-sdk`, from the HOST process. A spawned Winter session's
|
|
34
|
+
* children live inside that session's process, behind a pipe; without this facet the router owns a
|
|
35
|
+
* RuntimeDirectory that can address the session and nothing inside it, so WS-15 §6.2's "running
|
|
36
|
+
* Winter child" and "terminal Winter child" rows have no mechanism at all.
|
|
37
|
+
*
|
|
38
|
+
* WHAT IT IS NOT: the router. Every rule that needs the whole directory -- WS-10 §11's resolution
|
|
39
|
+
* order, ambiguity, staleness, §12's dedupe/retry ledger and loop guard, §13's hold/refuse policy --
|
|
40
|
+
* runs ABOVE this, in the host, once, for both runtimes. This is the six owner-specific operations
|
|
41
|
+
* the router delegates to whichever runtime actually holds the object.
|
|
42
|
+
*
|
|
43
|
+
* WINTER-ONLY, disclosed: the pinned official SDK has no messaging surface of any kind (its `Query`
|
|
44
|
+
* declares none), so there is no counterpart to mirror and nothing here is a divergence FROM one.
|
|
45
|
+
*
|
|
46
|
+
* FOUR THINGS A CONSUMER MUST KNOW, because none of them is visible in the signatures:
|
|
47
|
+
*
|
|
48
|
+
* 1. NO DELIVERY METHOD REJECTS. `deliver`, `steerChild`, `resumeChild` and `subscribeIdle` always
|
|
49
|
+
* RESOLVE with a typed `DeliveryOutcome` -- a caller that must record an outcome for every
|
|
50
|
+
* message (WS-10 §12's ledger) is never left with nothing to write down. A refusal the runtime
|
|
51
|
+
* could name arrives as `refused`; an unregistered messaging runtime as non-retryable
|
|
52
|
+
* `unavailable`; every other failure, including a transport fault, as `delivery_uncertain`,
|
|
53
|
+
* because from the host's side that is genuinely indistinguishable from "it already happened".
|
|
54
|
+
* 2. THIS FACET SERVES ONE SESSION -- its own, and its own children. A target naming another session
|
|
55
|
+
* is refused, even though the runtime could reach it in a shared process: cross-session delivery
|
|
56
|
+
* belongs to the router, through its directory, which is the one party that holds every session's
|
|
57
|
+
* entry and can pick the right adapter for it.
|
|
58
|
+
* 3. THE RECEIVER RE-RUNS INBOUND POLICY on the `senderPermissionClass` YOU stamped (WS-10 §13), so
|
|
59
|
+
* a caller-side decision to deliver can still come back `held` or `refused`. The envelope's class
|
|
60
|
+
* is an input to the receiver's matrix, never a verdict.
|
|
61
|
+
* 4. NOTIFICATIONS ARE NAMESPACED. `subscribeIdle` and `readNotifications` default to the FACET's own
|
|
62
|
+
* queue key (`host:<sessionId>`), deliberately separate from the one the session's own model
|
|
63
|
+
* drains with its `ReadNotifications` tool -- a drain REMOVES, so a shared key would have
|
|
64
|
+
* whichever side read first silently eat the other's notices. Passing
|
|
65
|
+
* `subscriberSessionId: <the session's own id>` opts into the model's bucket on purpose.
|
|
66
|
+
*/
|
|
67
|
+
export interface SessionMessagingFacet {
|
|
68
|
+
/** Every object this session can currently reach: its own children, plus the reachable live peers its adapter knows (WS-10 §10.2 -- never exited transcripts). */
|
|
69
|
+
listReachable(): Promise<ListedRuntimeObject[]>;
|
|
70
|
+
/** Deliver a fully-addressed envelope. The target is `msg.to`; the receiver's inbound policy (WS-10 §13) runs inside. */
|
|
71
|
+
deliver(msg: GlobalAgentMessage): Promise<DeliveryOutcome>;
|
|
72
|
+
/** Steer a RUNNING child (WS-10 §10.3). `id` is a canonical address or a bare child id within this session. */
|
|
73
|
+
steerChild(id: string, msg: GlobalAgentMessage): Promise<DeliveryOutcome>;
|
|
74
|
+
/** Resume a TERMINAL, addressable child (WS-10 §10.3). Never the reverse of `steerChild`. */
|
|
75
|
+
resumeChild(id: string, msg: GlobalAgentMessage): Promise<DeliveryOutcome>;
|
|
76
|
+
/**
|
|
77
|
+
* Subscribe to a target going idle (WS-10 §14). `opts.messageId` is the CALLER's -- the facet never
|
|
78
|
+
* allocates one, because allocation is keyed to the sender session plus tool-call id (§12) and a
|
|
79
|
+
* second allocator across the pipe would break the retry idempotency that key exists for.
|
|
80
|
+
* `subscriberSessionId` names whose notification queue the eventual notice belongs to; absent means
|
|
81
|
+
* the receiving session itself.
|
|
82
|
+
*/
|
|
83
|
+
subscribeIdle(id: string, opts: {
|
|
84
|
+
messageId: string;
|
|
85
|
+
subscriberSessionId?: string;
|
|
86
|
+
}): Promise<DeliveryOutcome>;
|
|
87
|
+
/** This session's own sender permission class (WS-10 §13's matrix input), from its LIVE permission mode. */
|
|
88
|
+
senderClass(): Promise<PermissionClassLabel>;
|
|
89
|
+
/**
|
|
90
|
+
* Drain a bounded page of queued notifications -- the CATCH-UP half of `notify_when_idle`
|
|
91
|
+
* (WS-15 §6.4's restart recovery). `remaining` says how many are still queued, so a host that
|
|
92
|
+
* reconnects drains in pages rather than in one frame whose size nothing governs.
|
|
93
|
+
*
|
|
94
|
+
* A drain is the ACKNOWLEDGEMENT: a record it returns is removed. `onIdleNotice` below carries the
|
|
95
|
+
* same notice live, with the same `notification_id`, so a host that got both dedupes on the id.
|
|
96
|
+
*/
|
|
97
|
+
readNotifications(opts?: {
|
|
98
|
+
subscriberSessionId?: string;
|
|
99
|
+
max?: number;
|
|
100
|
+
}): Promise<MessagingNotificationsPage>;
|
|
101
|
+
/**
|
|
102
|
+
* Subscribe to LIVE idle notices for this session. Returns an unsubscribe.
|
|
103
|
+
*
|
|
104
|
+
* A handler-plus-unsubscribe rather than an async iterator, because a notice is a fire-and-forget
|
|
105
|
+
* SIGNAL, not a stream a consumer may fall behind on: an iterator would need a buffer, and the
|
|
106
|
+
* durable buffer already exists on the runtime side (`readNotifications`). A handler that is never
|
|
107
|
+
* registered, or that throws, loses no notice -- the entry stays queued for the drain.
|
|
108
|
+
*/
|
|
109
|
+
onIdleNotice(handler: (payload: MessagingIdleNoticePayload) => void): () => void;
|
|
110
|
+
}
|
|
27
111
|
export interface Query extends AsyncGenerator<SdkMessage> {
|
|
28
112
|
interrupt(): Promise<void>;
|
|
29
113
|
setModel(model?: string): Promise<void>;
|
|
@@ -73,6 +157,13 @@ export interface Query extends AsyncGenerator<SdkMessage> {
|
|
|
73
157
|
dryRun?: boolean;
|
|
74
158
|
}): Promise<RewindFilesResult>;
|
|
75
159
|
setPermissionMode(mode: PermissionMode): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* R-7b-4: this session's messaging facet, backed by the six `messaging.*` control subtypes.
|
|
162
|
+
*
|
|
163
|
+
* ADDITIVE and Winter-only: the pinned `Query` contract loses nothing, and the official SDK has no
|
|
164
|
+
* member this could collide with. See `SessionMessagingFacet` for what it is and is not.
|
|
165
|
+
*/
|
|
166
|
+
messaging: SessionMessagingFacet;
|
|
76
167
|
__internal?: QueryInternal;
|
|
77
168
|
}
|
|
78
169
|
export declare function query(args: {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** The native `SendMessage` arguments (WS-10 §10.1), after validation. */
|
|
2
|
+
export interface NativeSendMessageArgs {
|
|
3
|
+
to: string;
|
|
4
|
+
message: string;
|
|
5
|
+
summary?: string;
|
|
6
|
+
notify_when_idle?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** The native `ListAgents` arguments (WS-10 §10.2). Both fields are reserved in the pinned build. */
|
|
9
|
+
export interface NativeListAgentsArgs {
|
|
10
|
+
channel?: string;
|
|
11
|
+
q?: string;
|
|
12
|
+
}
|
|
13
|
+
export type NativeArgsResult<T> = {
|
|
14
|
+
ok: true;
|
|
15
|
+
args: T;
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
reason: string;
|
|
19
|
+
};
|
|
20
|
+
/** Accepts the native `SendMessage` arguments EXACTLY — no more, no less. */
|
|
21
|
+
export declare function acceptNativeSendMessageArgs(input: unknown): NativeArgsResult<NativeSendMessageArgs>;
|
|
22
|
+
/** The same treatment for `ListAgents`: two reserved optional fields, both capped, nothing else. */
|
|
23
|
+
export declare function acceptNativeListAgentsArgs(input: unknown): NativeArgsResult<NativeListAgentsArgs>;
|
|
24
|
+
/**
|
|
25
|
+
* `ReadNotifications` takes the empty object, and only the empty object (ruling P-4).
|
|
26
|
+
*
|
|
27
|
+
* The Winter runtime's executor used to accept stray fields on the reasoning that an inert extra is
|
|
28
|
+
* not a reason to fail an otherwise-harmless call. That reasoning is right about HARM and wrong
|
|
29
|
+
* about SCHEMAS: a model that got away with `{ limit: 5 }` here has been told, by the runtime's own
|
|
30
|
+
* silence, that a `limit` exists.
|
|
31
|
+
*/
|
|
32
|
+
export declare function acceptNativeReadNotificationsArgs(input: unknown): NativeArgsResult<Record<string, never>>;
|
|
33
|
+
/**
|
|
34
|
+
* WS-10 §10.1: "summary?: derived from first message line when absent; truncated when overlong."
|
|
35
|
+
*
|
|
36
|
+
* NEVER a validation error — a computed value, or absent when there is nothing to derive from (the
|
|
37
|
+
* pure-idle-subscription case, whose message is empty by construction).
|
|
38
|
+
*/
|
|
39
|
+
export declare function deriveSendMessageSummary(rawSummary: string | undefined, message: string): string | undefined;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { SessionKey, SessionStore } from "../store/session-store.js";
|
|
2
|
+
import type { WinterToolHandler } from "./messaging-handlers.js";
|
|
3
|
+
/**
|
|
4
|
+
* One raw entry of a session's transcript — deliberately narrower/speech-shaped (who said what) than
|
|
5
|
+
* any host's own provider message type, which additionally carries structured content blocks for
|
|
6
|
+
* wire purposes this assembler has no need of.
|
|
7
|
+
*/
|
|
8
|
+
export interface TranscriptEntry {
|
|
9
|
+
role: "user" | "assistant" | "tool";
|
|
10
|
+
text: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* `getEntries` may be SYNCHRONOUS or async. The Winter runtime's real source is a live in-memory
|
|
14
|
+
* array captured by reference from the round loop (synchronous, and it must stay that way — a
|
|
15
|
+
* snapshot taken at wiring time would be empty forever); a host reading a durable transcript off
|
|
16
|
+
* disk needs the promise. The union is what lets one factory serve both.
|
|
17
|
+
*/
|
|
18
|
+
export interface TranscriptSource {
|
|
19
|
+
getEntries(): TranscriptEntry[] | Promise<TranscriptEntry[]>;
|
|
20
|
+
}
|
|
21
|
+
export interface AdvisorReviewerRequest {
|
|
22
|
+
messages: ReadonlyArray<{
|
|
23
|
+
role: "user" | "assistant" | "tool";
|
|
24
|
+
content: string;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export interface AdvisorReviewerTurn {
|
|
28
|
+
kind: string;
|
|
29
|
+
text?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface AdvisorReviewer {
|
|
32
|
+
generate(input: AdvisorReviewerRequest): Promise<AdvisorReviewerTurn>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolves BOTH the provider to call and the model id the result must report, TOGETHER: WS-06 §4's
|
|
36
|
+
* result shape pins `model: string` as required, but a provider interface has no `model` field to
|
|
37
|
+
* read back — whatever backs the reviewer capability must hand back the model id alongside the
|
|
38
|
+
* provider instance it resolved, in ONE seam, rather than two seams that could disagree.
|
|
39
|
+
*/
|
|
40
|
+
export interface ResolvedReviewer {
|
|
41
|
+
provider: AdvisorReviewer;
|
|
42
|
+
model: string;
|
|
43
|
+
}
|
|
44
|
+
/** `undefined` is the "no reviewer resolvable" case — WS-06 §4's ordinary tool error, never a throw. */
|
|
45
|
+
export type ReviewerResolver = () => ResolvedReviewer | undefined;
|
|
46
|
+
export interface AdvisorToolDeps {
|
|
47
|
+
transcriptSource: TranscriptSource;
|
|
48
|
+
resolveReviewer: ReviewerResolver;
|
|
49
|
+
/** Injectable so a host can pin the truncation boundary without a multi-KB fixture transcript. */
|
|
50
|
+
maxChars?: number;
|
|
51
|
+
}
|
|
52
|
+
export declare const ADVISOR_DEFAULT_MAX_CHARS = 20000;
|
|
53
|
+
/**
|
|
54
|
+
* RULING R3-3: "the assembler enforces the enforceable floor now — provider-opaque state
|
|
55
|
+
* (encrypted_content, signatures, reasoning items) is NEVER included."
|
|
56
|
+
*
|
|
57
|
+
* `thinking` and `redacted_thinking` are in the list because a probe fed both to a scripted reviewer
|
|
58
|
+
* as literal transcript text and both reached the wire verbatim, payload included, while the
|
|
59
|
+
* original three were correctly stripped. WS-06 §4's constraint reads "provider-opaque state", not
|
|
60
|
+
* "these three keys", and `redacted_thinking.data` is opaque by name.
|
|
61
|
+
*
|
|
62
|
+
* THE COST IS REAL AND ACCEPTED: "thinking" is an ordinary English word, so a review line that
|
|
63
|
+
* merely USES it ("I was thinking about the schema") is dropped along with the ones that carry a
|
|
64
|
+
* key. That is this function's declared posture — drop the whole line, never partially redact, fail
|
|
65
|
+
* toward the reviewer seeing less — and the price is one line of context in an advisory channel
|
|
66
|
+
* against a class of leak the transcript has no other guard for.
|
|
67
|
+
*/
|
|
68
|
+
export declare const OPAQUE_MARKERS: readonly ["encrypted_content", "reasoning_item", "signature", "thinking", "redacted_thinking"];
|
|
69
|
+
export declare function stripOpaqueMarkers(text: string): string;
|
|
70
|
+
/**
|
|
71
|
+
* Keeps the transcript TAIL (recent turns are what advice needs) and reports `truncated: true` only
|
|
72
|
+
* when something was actually clipped. Opaque-marker stripping runs PER ENTRY before truncation is
|
|
73
|
+
* measured, so a kept entry is always a whole, already-cleaned entry — truncation never bisects one,
|
|
74
|
+
* and a 4-KB `signature:` line never evicts the real conversation that came before it.
|
|
75
|
+
*/
|
|
76
|
+
export declare function assembleReviewerMessages(entries: readonly TranscriptEntry[], maxChars?: number): {
|
|
77
|
+
messages: Array<{
|
|
78
|
+
role: "user" | "assistant" | "tool";
|
|
79
|
+
content: string;
|
|
80
|
+
}>;
|
|
81
|
+
truncated: boolean;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* NO CACHE (WS-06 §4's closing line: "the advisor and the auto-mode classifier are separate routes
|
|
85
|
+
* and MUST NOT share a verdict cache"). Every call re-resolves the reviewer, re-assembles the
|
|
86
|
+
* transcript, and re-generates from scratch; nothing in this module is memoized, so there is nothing
|
|
87
|
+
* here that COULD be shared with a classifier's verdict cache even by accident.
|
|
88
|
+
*/
|
|
89
|
+
export declare function createAdvisorToolHandler(deps: AdvisorToolDeps): WinterToolHandler;
|
|
90
|
+
/**
|
|
91
|
+
* A `TranscriptSource` over the DURABLE transcript of one session.
|
|
92
|
+
*
|
|
93
|
+
* For a host that does not hold the live turn array — the router package, or any consumer wiring the
|
|
94
|
+
* advisor outside an engine's own closure. The Winter runtime keeps its in-memory source (the live
|
|
95
|
+
* `messages` array, captured by reference), because a resumed session's file and its live turns are
|
|
96
|
+
* not the same conversation until the turn ends.
|
|
97
|
+
*
|
|
98
|
+
* Reads through the pinned `SessionStore` interface so a host may inject an in-memory one; the
|
|
99
|
+
* default is the filesystem store over the resolved Winter home. A missing transcript is NO ENTRIES,
|
|
100
|
+
* never a throw: the advisor's whole posture is that an unavailable reviewer context degrades to an
|
|
101
|
+
* ordinary tool error rather than blocking the turn.
|
|
102
|
+
*/
|
|
103
|
+
export declare function transcriptSourceForSessionKey(key: SessionKey, opts?: {
|
|
104
|
+
store?: SessionStore;
|
|
105
|
+
winterHome?: string;
|
|
106
|
+
}): TranscriptSource;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type JsonSchemaObject } from "./schemas.js";
|
|
2
|
+
export interface WinterToolDefinition {
|
|
3
|
+
/** The BARE tool name: `send_message`, `list_agents`, `read_notifications`, `advisor`. */
|
|
4
|
+
readonly toolName: string;
|
|
5
|
+
/** The official SDK's built-in name for the same tool — the alias key a host binds under. */
|
|
6
|
+
readonly builtinName?: string;
|
|
7
|
+
readonly description: string;
|
|
8
|
+
/** Tool-Search terms, for a host that defers this tool. Advertised nowhere when it does not. */
|
|
9
|
+
readonly searchHint?: string;
|
|
10
|
+
readonly inputSchema: JsonSchemaObject;
|
|
11
|
+
readonly outputSchema?: JsonSchemaObject;
|
|
12
|
+
readonly annotations?: {
|
|
13
|
+
readOnlyHint?: boolean;
|
|
14
|
+
destructiveHint?: boolean;
|
|
15
|
+
openWorldHint?: boolean;
|
|
16
|
+
idempotentHint?: boolean;
|
|
17
|
+
title?: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* What the CALL does, not where the descriptor came from. `advisor` is `"mcp"` because it sends
|
|
21
|
+
* conversation content to a provider in the session's own trust domain (the same class of egress
|
|
22
|
+
* as the worker model's own requests), even though it registers as a bare built-in name.
|
|
23
|
+
*/
|
|
24
|
+
readonly permissionClass: "messaging" | "mcp";
|
|
25
|
+
}
|
|
26
|
+
export declare const SEND_MESSAGE_DEFINITION: WinterToolDefinition;
|
|
27
|
+
export declare const LIST_AGENTS_DEFINITION: WinterToolDefinition;
|
|
28
|
+
export declare const READ_NOTIFICATIONS_DEFINITION: WinterToolDefinition;
|
|
29
|
+
export declare const ADVISOR_DEFINITION: WinterToolDefinition;
|
|
30
|
+
/** The four, in the order a host registers them. */
|
|
31
|
+
export declare const WINTER_DEFAULT_TOOL_DEFINITIONS: readonly [typeof SEND_MESSAGE_DEFINITION, typeof LIST_AGENTS_DEFINITION, typeof READ_NOTIFICATIONS_DEFINITION, typeof ADVISOR_DEFINITION];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { SEND_MESSAGE_TO_MAX, SEND_MESSAGE_SUMMARY_MAX, LIST_AGENTS_FIELD_MAX, NATIVE_SEND_MESSAGE_SCHEMA, NATIVE_LIST_AGENTS_SCHEMA, NATIVE_LIST_AGENTS_OUTPUT_SCHEMA, NATIVE_READ_NOTIFICATIONS_SCHEMA, NATIVE_READ_NOTIFICATIONS_OUTPUT_SCHEMA, NATIVE_ADVISOR_SCHEMA, NATIVE_ADVISOR_OUTPUT_SCHEMA, } from "./schemas.js";
|
|
2
|
+
export type { JsonSchemaObject } from "./schemas.js";
|
|
3
|
+
export { SEND_MESSAGE_DEFINITION, LIST_AGENTS_DEFINITION, READ_NOTIFICATIONS_DEFINITION, ADVISOR_DEFINITION, WINTER_DEFAULT_TOOL_DEFINITIONS } from "./definitions.js";
|
|
4
|
+
export type { WinterToolDefinition } from "./definitions.js";
|
|
5
|
+
export { acceptNativeSendMessageArgs, acceptNativeListAgentsArgs, acceptNativeReadNotificationsArgs, deriveSendMessageSummary } from "./accept.js";
|
|
6
|
+
export type { NativeSendMessageArgs, NativeListAgentsArgs, NativeArgsResult } from "./accept.js";
|
|
7
|
+
export { messagingToolPortFromRuntimeDeps, callerAddress } from "./port.js";
|
|
8
|
+
export type { MessagingToolPort } from "./port.js";
|
|
9
|
+
export { createMessagingToolHandlers, toolUseIdFromExtra, VENDOR_TOOL_USE_ID_META_KEY } from "./messaging-handlers.js";
|
|
10
|
+
export type { WinterToolCaller, WinterToolResult, WinterToolHandler, MessagingToolHandlers } from "./messaging-handlers.js";
|
|
11
|
+
export { ADVISOR_DEFAULT_MAX_CHARS, OPAQUE_MARKERS, stripOpaqueMarkers, assembleReviewerMessages, createAdvisorToolHandler, transcriptSourceForSessionKey } from "./advisor.js";
|
|
12
|
+
export type { TranscriptEntry, TranscriptSource, AdvisorReviewerRequest, AdvisorReviewerTurn, AdvisorReviewer, ResolvedReviewer, ReviewerResolver, AdvisorToolDeps } from "./advisor.js";
|
|
13
|
+
export type { RuntimeAddress, ListedRuntimeObject, SendMessageResult, NotificationRecord, MessagingRuntimeDeps } from "../messaging/index.js";
|
|
14
|
+
export type { SessionKey, SessionStore } from "../store/session-store.js";
|