@otto-code/protocol 0.7.5 → 0.8.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/agent-attention-notification.d.ts +2 -0
- package/dist/agent-attention-notification.js +2 -1
- package/dist/agent-deep-link.d.ts +8 -0
- package/dist/agent-deep-link.js +49 -0
- package/dist/agent-labels.js +4 -4
- package/dist/agent-personalities.d.ts +2 -2
- package/dist/agent-personalities.js +17 -17
- package/dist/agent-teams.d.ts +4 -4
- package/dist/agent-teams.js +5 -5
- package/dist/agent-types.d.ts +12 -10
- package/dist/agent-types.js +1 -1
- package/dist/artifacts/rpc-schemas.js +4 -4
- package/dist/artifacts/types.js +3 -3
- package/dist/binary-frames/file-transfer.d.ts +1 -0
- package/dist/binary-frames/file-transfer.js +1 -0
- package/dist/browser-automation/rpc-schemas.js +1 -1
- package/dist/client-capabilities.d.ts +3 -0
- package/dist/client-capabilities.js +9 -0
- package/dist/daemon-endpoints.d.ts +1 -1
- package/dist/default-personalities.js +11 -11
- package/dist/effort.d.ts +1 -1
- package/dist/effort.js +2 -2
- package/dist/forge-manifest.d.ts +66 -0
- package/dist/forge-manifest.js +92 -0
- package/dist/generated/validation/ws-outbound.aot.js +77653 -51519
- package/dist/git-hosting.js +3 -3
- package/dist/git-remote.d.ts +17 -0
- package/dist/git-remote.js +23 -2
- package/dist/judge-verdict.d.ts +1 -1
- package/dist/judge-verdict.js +2 -2
- package/dist/messages.d.ts +10634 -135
- package/dist/messages.js +1744 -193
- package/dist/model-tiers.d.ts +3 -3
- package/dist/model-tiers.js +4 -4
- package/dist/observed-subagent-title.d.ts +2 -2
- package/dist/observed-subagent-title.js +4 -4
- package/dist/orchestration.d.ts +3 -3
- package/dist/orchestration.js +32 -32
- package/dist/otto-config-schema.d.ts +21 -0
- package/dist/otto-config-schema.js +23 -1
- package/dist/provider-config.d.ts +92 -3
- package/dist/provider-config.js +58 -6
- package/dist/provider-manifest.d.ts +11 -1
- package/dist/provider-manifest.js +53 -5
- package/dist/schedule/cadence.d.ts +6 -0
- package/dist/schedule/cadence.js +28 -0
- package/dist/schedule/rpc-schemas.d.ts +4 -4
- package/dist/schedule/rpc-schemas.js +1 -1
- package/dist/schedule/types.d.ts +1 -1
- package/dist/schedule/types.js +3 -3
- package/dist/tool-call-display.d.ts +1 -1
- package/dist/tool-call-display.js +3 -3
- package/dist/tool-name-normalization.d.ts +2 -2
- package/dist/tool-name-normalization.js +2 -2
- package/dist/validation/ws-outbound-schema-metadata.d.ts +1950 -52
- package/dist/widgets/bridge.d.ts +5 -5
- package/dist/widgets/bridge.js +5 -5
- package/dist/widgets/document.d.ts +1 -1
- package/dist/widgets/document.js +4 -4
- package/dist/widgets/icons.d.ts +1 -1
- package/dist/widgets/icons.js +1 -1
- package/dist/widgets/theme.d.ts +2 -2
- package/dist/widgets/theme.js +2 -2
- package/dist/widgets/types.d.ts +5 -5
- package/dist/widgets/types.js +5 -5
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ export type AgentAttentionReason = "finished" | "error" | "permission";
|
|
|
2
2
|
export interface AgentAttentionNotificationData {
|
|
3
3
|
[key: string]: unknown;
|
|
4
4
|
serverId: string;
|
|
5
|
+
workspaceId?: string;
|
|
5
6
|
agentId: string;
|
|
6
7
|
reason: AgentAttentionReason;
|
|
7
8
|
}
|
|
@@ -13,6 +14,7 @@ export interface AgentAttentionNotificationPayload {
|
|
|
13
14
|
interface BuildAgentAttentionNotificationPayloadInput {
|
|
14
15
|
reason: AgentAttentionReason;
|
|
15
16
|
serverId: string;
|
|
17
|
+
workspaceId: string;
|
|
16
18
|
agentId: string;
|
|
17
19
|
assistantMessage?: string | null;
|
|
18
20
|
permissionRequest?: NotificationPermissionRequest | null;
|
|
@@ -74,7 +74,7 @@ const PERMISSION_INPUT_DESCRIPTION_KEYS = [
|
|
|
74
74
|
"query",
|
|
75
75
|
"prompt",
|
|
76
76
|
];
|
|
77
|
-
// Deterministic field extraction
|
|
77
|
+
// Deterministic field extraction - NOT an AI summary. Picks an existing string
|
|
78
78
|
// field out of the tool's input (by the priority list, then any string field)
|
|
79
79
|
// so the notification can show it verbatim instead of raw JSON.
|
|
80
80
|
const describePermissionInput = (input) => {
|
|
@@ -180,6 +180,7 @@ export function buildAgentAttentionNotificationPayload(input) {
|
|
|
180
180
|
body,
|
|
181
181
|
data: {
|
|
182
182
|
serverId: input.serverId,
|
|
183
|
+
workspaceId: input.workspaceId,
|
|
183
184
|
agentId: input.agentId,
|
|
184
185
|
reason: input.reason,
|
|
185
186
|
},
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface AgentDeepLinkTarget {
|
|
2
|
+
serverId: string;
|
|
3
|
+
agentId: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function buildAgentDeepLinkRoute(target: AgentDeepLinkTarget): `/h/${string}/agent/${string}`;
|
|
6
|
+
export declare function buildAgentDeepLink(target: AgentDeepLinkTarget): string;
|
|
7
|
+
export declare function parseAgentDeepLink(input: string): AgentDeepLinkTarget | null;
|
|
8
|
+
//# sourceMappingURL=agent-deep-link.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
function normalizeSegment(value) {
|
|
2
|
+
return value.trim();
|
|
3
|
+
}
|
|
4
|
+
function normalizeAgentDeepLinkTarget(target) {
|
|
5
|
+
const serverId = normalizeSegment(target.serverId);
|
|
6
|
+
const agentId = normalizeSegment(target.agentId);
|
|
7
|
+
if (!serverId || !agentId) {
|
|
8
|
+
throw new Error("Agent deep links require a server ID and agent ID.");
|
|
9
|
+
}
|
|
10
|
+
return { serverId, agentId };
|
|
11
|
+
}
|
|
12
|
+
export function buildAgentDeepLinkRoute(target) {
|
|
13
|
+
const { serverId, agentId } = normalizeAgentDeepLinkTarget(target);
|
|
14
|
+
return `/h/${encodeURIComponent(serverId)}/agent/${encodeURIComponent(agentId)}`;
|
|
15
|
+
}
|
|
16
|
+
export function buildAgentDeepLink(target) {
|
|
17
|
+
return `otto:/${buildAgentDeepLinkRoute(target)}`;
|
|
18
|
+
}
|
|
19
|
+
export function parseAgentDeepLink(input) {
|
|
20
|
+
let url;
|
|
21
|
+
try {
|
|
22
|
+
url = new URL(input);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
if (url.protocol !== "otto:" ||
|
|
28
|
+
url.hostname !== "h" ||
|
|
29
|
+
url.username ||
|
|
30
|
+
url.password ||
|
|
31
|
+
url.port ||
|
|
32
|
+
url.search ||
|
|
33
|
+
url.hash) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
37
|
+
if (segments.length !== 3 || segments[1] !== "agent") {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const serverId = normalizeSegment(decodeURIComponent(segments[0] ?? ""));
|
|
42
|
+
const agentId = normalizeSegment(decodeURIComponent(segments[2] ?? ""));
|
|
43
|
+
return serverId && agentId ? { serverId, agentId } : null;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=agent-deep-link.js.map
|
package/dist/agent-labels.js
CHANGED
|
@@ -11,9 +11,9 @@ export function isDelegatedAgent(agent) {
|
|
|
11
11
|
// ── Orchestration node labels (projects/orchestration-graphs) ───────────────
|
|
12
12
|
// Stamped by the daemon on agents it spawns as orchestration participants. The
|
|
13
13
|
// otto-tool catalog reads the policy label to enforce the tool binary:
|
|
14
|
-
// "deterministic"
|
|
14
|
+
// "deterministic" - the daemon does all linking; the node gets NO orchestration
|
|
15
15
|
// tools (spawning/steering agents, runs), NO preview/dev-server tools, and NO
|
|
16
|
-
// browser tools. "autonomous"
|
|
16
|
+
// browser tools. "autonomous" - full otto toolset EXCEPT start_run
|
|
17
17
|
// (orchestrations never nest orchestrations).
|
|
18
18
|
export const ORCHESTRATION_POLICY_LABEL = "otto.orchestration-policy";
|
|
19
19
|
export const ORCHESTRATION_POLICIES = ["deterministic", "autonomous"];
|
|
@@ -26,10 +26,10 @@ export function getOrchestrationPolicyFromLabels(labels) {
|
|
|
26
26
|
export const ORCHESTRATION_RUN_ID_LABEL = "otto.orchestration-run-id";
|
|
27
27
|
// The node's declared output fields, JSON-encoded, stamped on the spawned
|
|
28
28
|
// agent. The otto-tool catalog reads it to register that agent's submit_output
|
|
29
|
-
// tool
|
|
29
|
+
// tool - which is why this rides a label rather than a spawn option: the
|
|
30
30
|
// catalog is built per agent from the agent's own record, so every provider
|
|
31
31
|
// (MCP-served and native-loop alike) inherits the tool with no per-provider
|
|
32
|
-
// plumbing. Malformed JSON reads as "no declared fields"
|
|
32
|
+
// plumbing. Malformed JSON reads as "no declared fields" - a node that can't
|
|
33
33
|
// parse its own contract falls back to prose rather than failing to spawn.
|
|
34
34
|
export const ORCHESTRATION_OUTPUT_FIELDS_LABEL = "otto.orchestration-output-fields";
|
|
35
35
|
export function getOutputFieldsFromLabels(labels) {
|
|
@@ -24,7 +24,7 @@ export declare function personalityCanLaunch(personality: Pick<AgentPersonality,
|
|
|
24
24
|
export interface PersonalitySelectionSummary {
|
|
25
25
|
tier: PersonalityRoleTier;
|
|
26
26
|
canLaunch: boolean;
|
|
27
|
-
/** The "why you'd choose me" blurb
|
|
27
|
+
/** The "why you'd choose me" blurb - each of the personality's roles, joined. */
|
|
28
28
|
guidance: string;
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
@@ -40,7 +40,7 @@ export declare const ORCHESTRATOR_METHOD_DIRECTIVE: string;
|
|
|
40
40
|
* spawn. The orchestrator gets the full conductor method; other coordinators
|
|
41
41
|
* (chatter/artificer/scheduler) get a lighter delegate nudge; focused workers
|
|
42
42
|
* are told to stay on the task someone is waiting on. Roleless spawns get
|
|
43
|
-
* nothing. This is guidance, not a gate
|
|
43
|
+
* nothing. This is guidance, not a gate - the tools stay available either way.
|
|
44
44
|
*/
|
|
45
45
|
export declare function composeRoleFocusDirective(roles: readonly string[] | undefined): string | undefined;
|
|
46
46
|
export type PersonalityUnavailableCode = "provider-missing" | "provider-disabled" | "provider-not-ready" | "model-missing" | "mode-missing";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PERSONALITY_ROLES } from "./messages.js";
|
|
2
2
|
// Pure, dependency-free personality helpers shared by the daemon (spawn-time
|
|
3
3
|
// resolution) and the app (picker availability + role filtering). Effort
|
|
4
|
-
// resolution is NOT here
|
|
4
|
+
// resolution is NOT here - it needs the model's advertised thinking options and
|
|
5
5
|
// lives with the daemon's effort resolver; availability does not depend on it.
|
|
6
6
|
const ROLE_SET = new Set(PERSONALITY_ROLES);
|
|
7
7
|
// Retired role names, mapped to their canonical replacement. "worker" was split
|
|
@@ -41,7 +41,7 @@ export const PERSONALITY_ROLE_INFO = {
|
|
|
41
41
|
// ── Surfaces ──────────────────────────────────────────────────────────────
|
|
42
42
|
chatter: {
|
|
43
43
|
tier: "coordinator",
|
|
44
|
-
guidance: "Interactive driver
|
|
44
|
+
guidance: "Interactive driver - converse, plan, and delegate. Pick to run a chat or coordinate work.",
|
|
45
45
|
},
|
|
46
46
|
artificer: {
|
|
47
47
|
tier: "coordinator",
|
|
@@ -54,37 +54,37 @@ export const PERSONALITY_ROLE_INFO = {
|
|
|
54
54
|
// ── Thinking workers (read-only, structured findings) ─────────────────────
|
|
55
55
|
researcher: {
|
|
56
56
|
tier: "focused",
|
|
57
|
-
guidance: "Read-only surveyor
|
|
57
|
+
guidance: "Read-only surveyor - maps the code or domain and reports files, types, patterns, and gotchas. Pick to gather facts; proposes no solutions and edits nothing.",
|
|
58
58
|
},
|
|
59
59
|
planner: {
|
|
60
60
|
tier: "focused",
|
|
61
|
-
guidance: "Planning specialist
|
|
61
|
+
guidance: "Planning specialist - turns a goal into a typed, sequenced phase plan for others to execute. Pick to draft an actionable plan; stays on the plan and doesn't dispatch.",
|
|
62
62
|
},
|
|
63
63
|
judger: {
|
|
64
64
|
tier: "focused",
|
|
65
|
-
guidance: "Review specialist
|
|
65
|
+
guidance: "Review specialist - evaluates work or a plan against criteria and returns a structured verdict. Pick for a focused review; stays on task.",
|
|
66
66
|
},
|
|
67
67
|
advisor: {
|
|
68
68
|
tier: "focused",
|
|
69
|
-
guidance: "Read-only second opinion
|
|
69
|
+
guidance: "Read-only second opinion - weighs the trade-offs and returns one recommendation. Pick for advice; never edits and does not fan out.",
|
|
70
70
|
},
|
|
71
71
|
// ── Making workers (produce code, design, or text) ────────────────────────
|
|
72
72
|
coder: {
|
|
73
73
|
tier: "focused",
|
|
74
|
-
guidance: "Focused implementer
|
|
74
|
+
guidance: "Focused implementer - writes code for one sub-task others are waiting on. Pick to get a coding job done; stays on task.",
|
|
75
75
|
},
|
|
76
76
|
designer: {
|
|
77
77
|
tier: "focused",
|
|
78
|
-
guidance: "Design maker
|
|
78
|
+
guidance: "Design maker - styling and layout plus the human-skill text (copy, naming). Pick for the look-and-feel or the words; stays on task.",
|
|
79
79
|
},
|
|
80
80
|
writer: {
|
|
81
81
|
tier: "focused",
|
|
82
|
-
guidance: "Fast small-text specialist
|
|
82
|
+
guidance: "Fast small-text specialist - commit messages, summaries, names. Pick for quick text; stays on the one task.",
|
|
83
83
|
},
|
|
84
84
|
// ── Conductor ─────────────────────────────────────────────────────────────
|
|
85
85
|
orchestrator: {
|
|
86
86
|
tier: "coordinator",
|
|
87
|
-
guidance: "The sole conductor
|
|
87
|
+
guidance: "The sole conductor - plans team-shaped work, dispatches typed tasks to the right teammates, gathers, and synthesizes. Pick to run a multi-agent workflow.",
|
|
88
88
|
},
|
|
89
89
|
};
|
|
90
90
|
/**
|
|
@@ -111,21 +111,21 @@ export function summarizePersonalityForSelection(personality) {
|
|
|
111
111
|
guidance: roles.map((role) => PERSONALITY_ROLE_INFO[role].guidance).join(" "),
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
|
-
// The conductor's standing directive
|
|
114
|
+
// The conductor's standing directive - the distilled `/epic` method taught to
|
|
115
115
|
// the sole orchestrator role at spawn, so orchestration is emergent (the agent
|
|
116
116
|
// recognizes team-shaped work and runs it) rather than something a user must
|
|
117
117
|
// invoke. Kept here as one exported constant so the wording is testable and
|
|
118
118
|
// shared. See projects/agent-orchestration/agent-orchestration.md.
|
|
119
|
-
export const ORCHESTRATOR_METHOD_DIRECTIVE = "You are the orchestrator
|
|
120
|
-
"First apply the complexity gate: if a task is small and not splittable, just do it
|
|
121
|
-
"When you do orchestrate: (1) if the shape is unclear, dispatch a researcher to survey and a planner to draft a typed plan; (2) declare that plan as a Run with start_run
|
|
122
|
-
"Prefer start_run over hand-spawning and tracking agents yourself
|
|
119
|
+
export const ORCHESTRATOR_METHOD_DIRECTIVE = "You are the orchestrator - the team's sole conductor. Team-shaped work is yours to run, and you should reach for it naturally, not only when asked. " +
|
|
120
|
+
"First apply the complexity gate: if a task is small and not splittable, just do it - no ceremony. Only orchestrate when the work is large, parallelizable, or benefits from independent perspectives. " +
|
|
121
|
+
"When you do orchestrate: (1) if the shape is unclear, dispatch a researcher to survey and a planner to draft a typed plan; (2) declare that plan as a Run with start_run - phases typed research/plan/implement/design/verify/gate/deliver, fanning out candidates where several angles help and attaching a judger to grade them, looping until enough pass; (3) put a gate before irreversible or costly steps so the user approves; (4) synthesize the passing results into the deliverable. " +
|
|
122
|
+
"Prefer start_run over hand-spawning and tracking agents yourself - the runtime fans out, gathers typed verdicts, and enforces the loop for you. Every phase maps to a teammate's role; if the active team lacks a role a phase needs, say so plainly and stop rather than papering over the gap.";
|
|
123
123
|
/**
|
|
124
124
|
* The in-context "role directive" injected into a personality's system prompt at
|
|
125
125
|
* spawn. The orchestrator gets the full conductor method; other coordinators
|
|
126
126
|
* (chatter/artificer/scheduler) get a lighter delegate nudge; focused workers
|
|
127
127
|
* are told to stay on the task someone is waiting on. Roleless spawns get
|
|
128
|
-
* nothing. This is guidance, not a gate
|
|
128
|
+
* nothing. This is guidance, not a gate - the tools stay available either way.
|
|
129
129
|
*/
|
|
130
130
|
export function composeRoleFocusDirective(roles) {
|
|
131
131
|
const normalized = normalizePersonalityRoles(roles);
|
|
@@ -139,7 +139,7 @@ export function composeRoleFocusDirective(roles) {
|
|
|
139
139
|
if (normalized.some((role) => PERSONALITY_ROLE_INFO[role].tier === "coordinator")) {
|
|
140
140
|
return `You are a coordinator personality (roles: ${roleList}). You front interactive work and may delegate: use list_personalities to see who else is available, and spawn other agents or hand off to the team's orchestrator whenever delegating gets the work done faster or better.`;
|
|
141
141
|
}
|
|
142
|
-
return `You are a focused worker personality (roles: ${roleList}). Someone is waiting on this specific task
|
|
142
|
+
return `You are a focused worker personality (roles: ${roleList}). Someone is waiting on this specific task - stay on it and finish it. You can still call list_personalities to see the roster, but don't spawn sub-agents or start side workflows unless it is genuinely essential to completing this job.`;
|
|
143
143
|
}
|
|
144
144
|
/**
|
|
145
145
|
* Decide whether a personality is usable against a provider's current snapshot.
|
package/dist/agent-teams.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { AgentPersonality, AgentTeam, PersonalityRole } from "./messages.js
|
|
|
3
3
|
* The dynamic "Team's Scheduler" schedule binding. Stored in the schedule's
|
|
4
4
|
* `personality` field in place of a personality name; resolved at RUN time to
|
|
5
5
|
* the active team's first available member carrying the Scheduler role
|
|
6
|
-
* (member order). Deliberately contains "@"
|
|
6
|
+
* (member order). Deliberately contains "@" - personality names are sanitized
|
|
7
7
|
* to [A-Za-z0-9_-] at the authoring surface, so the sentinel can never collide
|
|
8
8
|
* with a real name. No active team, or no available Scheduler member, is a
|
|
9
9
|
* hard run failure with a named error (same loudness as a bound personality
|
|
@@ -17,7 +17,7 @@ export interface AgentTeamsConfigView {
|
|
|
17
17
|
export declare function findAgentTeam(teams: readonly AgentTeam[] | undefined, teamId: string | null | undefined): AgentTeam | null;
|
|
18
18
|
/**
|
|
19
19
|
* Resolve the host's active team. A dangling `activeTeamId` (team deleted, or
|
|
20
|
-
* a patch raced a delete) reads as "no team active"
|
|
20
|
+
* a patch raced a delete) reads as "no team active" - teamlessness is a valid
|
|
21
21
|
* state and must never error. The daemon additionally heals a dangling id back
|
|
22
22
|
* to null on the next config patch; this helper is the read-side tolerance.
|
|
23
23
|
*/
|
|
@@ -42,13 +42,13 @@ export declare function pruneTeamMemberIds(memberIds: readonly string[] | undefi
|
|
|
42
42
|
* team at all, so the delete confirm can offer to clean them up. Dangling member
|
|
43
43
|
* ids resolve to nothing and drop out, same as everywhere else.
|
|
44
44
|
*
|
|
45
|
-
* Pass the teams that will REMAIN after the delete
|
|
45
|
+
* Pass the teams that will REMAIN after the delete - the caller owns the filter,
|
|
46
46
|
* so this stays a pure set operation with no notion of "the team being deleted".
|
|
47
47
|
*/
|
|
48
48
|
export declare function resolveExclusiveTeamMembers(team: Pick<AgentTeam, "memberIds"> | null | undefined, otherTeams: readonly Pick<AgentTeam, "memberIds">[] | undefined, personalities: readonly AgentPersonality[] | undefined): AgentPersonality[];
|
|
49
49
|
/**
|
|
50
50
|
* The union of all members' roles, normalized and returned in canonical
|
|
51
|
-
* `PERSONALITY_ROLES` order
|
|
51
|
+
* `PERSONALITY_ROLES` order - the team card's role-pill strip.
|
|
52
52
|
*/
|
|
53
53
|
export declare function teamRoleUnion(team: Pick<AgentTeam, "memberIds"> | null | undefined, personalities: readonly AgentPersonality[] | undefined): PersonalityRole[];
|
|
54
54
|
/**
|
package/dist/agent-teams.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { normalizePersonalityRoles } from "./agent-personalities.js";
|
|
2
2
|
// Pure, dependency-free team helpers shared by the daemon (spawn-time active
|
|
3
3
|
// team resolution, list_personalities scoping) and the app (team cards,
|
|
4
|
-
// pickers, the Active Team switcher). Availability is deliberately NOT here
|
|
4
|
+
// pickers, the Active Team switcher). Availability is deliberately NOT here -
|
|
5
5
|
// a team is never "out of commission"; its members are individually available
|
|
6
6
|
// or not, judged by checkPersonalityAvailability per member.
|
|
7
7
|
/**
|
|
8
8
|
* The dynamic "Team's Scheduler" schedule binding. Stored in the schedule's
|
|
9
9
|
* `personality` field in place of a personality name; resolved at RUN time to
|
|
10
10
|
* the active team's first available member carrying the Scheduler role
|
|
11
|
-
* (member order). Deliberately contains "@"
|
|
11
|
+
* (member order). Deliberately contains "@" - personality names are sanitized
|
|
12
12
|
* to [A-Za-z0-9_-] at the authoring surface, so the sentinel can never collide
|
|
13
13
|
* with a real name. No active team, or no available Scheduler member, is a
|
|
14
14
|
* hard run failure with a named error (same loudness as a bound personality
|
|
@@ -23,7 +23,7 @@ export function findAgentTeam(teams, teamId) {
|
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Resolve the host's active team. A dangling `activeTeamId` (team deleted, or
|
|
26
|
-
* a patch raced a delete) reads as "no team active"
|
|
26
|
+
* a patch raced a delete) reads as "no team active" - teamlessness is a valid
|
|
27
27
|
* state and must never error. The daemon additionally heals a dangling id back
|
|
28
28
|
* to null on the next config patch; this helper is the read-side tolerance.
|
|
29
29
|
*/
|
|
@@ -86,7 +86,7 @@ export function pruneTeamMemberIds(memberIds, personalities) {
|
|
|
86
86
|
* team at all, so the delete confirm can offer to clean them up. Dangling member
|
|
87
87
|
* ids resolve to nothing and drop out, same as everywhere else.
|
|
88
88
|
*
|
|
89
|
-
* Pass the teams that will REMAIN after the delete
|
|
89
|
+
* Pass the teams that will REMAIN after the delete - the caller owns the filter,
|
|
90
90
|
* so this stays a pure set operation with no notion of "the team being deleted".
|
|
91
91
|
*/
|
|
92
92
|
export function resolveExclusiveTeamMembers(team, otherTeams, personalities) {
|
|
@@ -100,7 +100,7 @@ export function resolveExclusiveTeamMembers(team, otherTeams, personalities) {
|
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
102
|
* The union of all members' roles, normalized and returned in canonical
|
|
103
|
-
* `PERSONALITY_ROLES` order
|
|
103
|
+
* `PERSONALITY_ROLES` order - the team card's role-pill strip.
|
|
104
104
|
*/
|
|
105
105
|
export function teamRoleUnion(team, personalities) {
|
|
106
106
|
const roles = resolveTeamMembers(team, personalities).flatMap((personality) => personality.roles ?? []);
|
package/dist/agent-types.d.ts
CHANGED
|
@@ -110,6 +110,7 @@ export interface ProviderSnapshotEntry {
|
|
|
110
110
|
provider: AgentProvider;
|
|
111
111
|
status: ProviderStatus;
|
|
112
112
|
enabled: boolean;
|
|
113
|
+
source?: "builtin" | "custom";
|
|
113
114
|
error?: string;
|
|
114
115
|
models?: AgentModelDefinition[];
|
|
115
116
|
modes?: AgentMode[];
|
|
@@ -177,18 +178,18 @@ export interface AgentRunOptions {
|
|
|
177
178
|
* origin. Powers the visualizer's context ring/bar colored segments (the same
|
|
178
179
|
* five categories the vendored render layer draws). Every field is optional and
|
|
179
180
|
* a token count: a provider fills as many categories as it can attribute and
|
|
180
|
-
* omits the rest, so richness degrades gracefully per provider
|
|
181
|
+
* omits the rest, so richness degrades gracefully per provider - Claude
|
|
181
182
|
* attributes the most; a provider that can attribute nothing omits the whole
|
|
182
183
|
* object and consumers fall back to occupancy-only (no colored segments, the
|
|
183
184
|
* pre-composition behavior). Counts are best-effort estimates, not billed usage;
|
|
184
185
|
* they need not sum exactly to `contextWindowUsedTokens` (the consumer scales).
|
|
185
186
|
*/
|
|
186
187
|
export interface ContextComposition {
|
|
187
|
-
/** System prompt + tool/function definitions
|
|
188
|
+
/** System prompt + tool/function definitions - the fixed base cost. */
|
|
188
189
|
systemPrompt?: number;
|
|
189
190
|
/** User-authored input messages. */
|
|
190
191
|
userMessages?: number;
|
|
191
|
-
/** Tool results
|
|
192
|
+
/** Tool results - file contents, search output, command output (usually the
|
|
192
193
|
* largest and most volatile category). */
|
|
193
194
|
toolResults?: number;
|
|
194
195
|
/** The agent's own reasoning / thinking blocks. */
|
|
@@ -198,14 +199,14 @@ export interface ContextComposition {
|
|
|
198
199
|
}
|
|
199
200
|
/**
|
|
200
201
|
* One provider-reported context-window category. `name` is a provider-supplied
|
|
201
|
-
* *display label* ("Messages", "System prompt", "MCP tools")
|
|
202
|
+
* *display label* ("Messages", "System prompt", "MCP tools") - deliberately an
|
|
202
203
|
* OPEN-ENDED string and not an enum, so each provider reports the split it
|
|
203
204
|
* actually has instead of being squeezed into categories it can't populate.
|
|
204
205
|
*
|
|
205
206
|
* Structurally identical to `AgentContextUsageCategory` on the pull path
|
|
206
207
|
* (`agent.context.get_usage`, see messages.ts) *by design*: the two carry the
|
|
207
208
|
* same accounting, one pushed on the agent snapshot and one pulled on demand.
|
|
208
|
-
* Keep them in sync
|
|
209
|
+
* Keep them in sync - a divergence here is how the context meter and the
|
|
209
210
|
* visualizer would start disagreeing about the same agent.
|
|
210
211
|
*/
|
|
211
212
|
export interface AgentContextCategory {
|
|
@@ -218,7 +219,7 @@ export interface AgentUsage {
|
|
|
218
219
|
inputTokens?: number;
|
|
219
220
|
cachedInputTokens?: number;
|
|
220
221
|
/**
|
|
221
|
-
* Prompt tokens spent writing (not reading) the prompt cache this turn
|
|
222
|
+
* Prompt tokens spent writing (not reading) the prompt cache this turn -
|
|
222
223
|
* Anthropic's `cache_creation_input_tokens`, billed above normal input.
|
|
223
224
|
* Disjoint from `inputTokens`/`cachedInputTokens`. Claude-specific today;
|
|
224
225
|
* other providers omit it. Optional/additive.
|
|
@@ -235,7 +236,7 @@ export interface AgentUsage {
|
|
|
235
236
|
*/
|
|
236
237
|
contextComposition?: ContextComposition;
|
|
237
238
|
/**
|
|
238
|
-
* The provider's OWN context-window split, with its own labels
|
|
239
|
+
* The provider's OWN context-window split, with its own labels - the same
|
|
239
240
|
* accounting the `agent.context.get_usage` RPC returns, pushed here on the
|
|
240
241
|
* agent snapshot so stream/backfill consumers (the visualizer) read the very
|
|
241
242
|
* numbers the context meter shows rather than a parallel estimate.
|
|
@@ -373,6 +374,7 @@ export type AgentTimelineItem = {
|
|
|
373
374
|
type: "user_message";
|
|
374
375
|
text: string;
|
|
375
376
|
messageId?: string;
|
|
377
|
+
clientMessageId?: string;
|
|
376
378
|
} | {
|
|
377
379
|
type: "assistant_message";
|
|
378
380
|
text: string;
|
|
@@ -490,7 +492,7 @@ export interface ObservedSubagentUpdate {
|
|
|
490
492
|
requiresAttention?: boolean;
|
|
491
493
|
usage?: AgentUsage;
|
|
492
494
|
/**
|
|
493
|
-
* True once this run is known to outlive an interrupt of the parent's turn
|
|
495
|
+
* True once this run is known to outlive an interrupt of the parent's turn -
|
|
494
496
|
* the provider backgrounded it, so the parent's teardown does not take it
|
|
495
497
|
* down. Sticky: the daemon keeps it set for the row's whole life, and
|
|
496
498
|
* propagates it to nested rows (a child of a backgrounded run survives too).
|
|
@@ -509,7 +511,7 @@ export interface ObservedSubagentUpdate {
|
|
|
509
511
|
*/
|
|
510
512
|
toolUseCount?: number;
|
|
511
513
|
/**
|
|
512
|
-
* The tool this subagent is running (or ran last)
|
|
514
|
+
* The tool this subagent is running (or ran last) - the "spinning _on a 90s
|
|
513
515
|
* Bash_" signal. Neutral field any provider can set; unlike the counters it is
|
|
514
516
|
* NOT monotonic (latest wins) and the daemon drops it once the row goes
|
|
515
517
|
* terminal. Claude reads it from `task_progress.last_tool_name`. Absent ⇒ the
|
|
@@ -521,7 +523,7 @@ export interface ObservedSubagentUpdate {
|
|
|
521
523
|
* A background shell task reported by a provider's own Bash tool (Claude:
|
|
522
524
|
* `run_in_background`). `key` is a provider-local stable identifier (Claude:
|
|
523
525
|
* the Bash tool_use id); the daemon namespaces it under the owning agent.
|
|
524
|
-
* Unlike {@link ObservedSubagentUpdate} this has no transcript/pane
|
|
526
|
+
* Unlike {@link ObservedSubagentUpdate} this has no transcript/pane - it's a
|
|
525
527
|
* plain status row (command, status, elapsed) in the Background Tasks track.
|
|
526
528
|
*/
|
|
527
529
|
export interface BackgroundShellTaskUpdate {
|
package/dist/agent-types.js
CHANGED
|
@@ -26,7 +26,7 @@ export function getAgentStreamEventTurnId(event) {
|
|
|
26
26
|
// accept the setting and ignore it.
|
|
27
27
|
//
|
|
28
28
|
// This is a *boundary*, not an instruction. "read" means the write tools are
|
|
29
|
-
// not offered, so there is no write to make
|
|
29
|
+
// not offered, so there is no write to make - never a line of prompt asking the
|
|
30
30
|
// model to behave. A control a user relies on when deciding to run something
|
|
31
31
|
// unattended has to be true in exactly the cases where the model is confused.
|
|
32
32
|
export const WORKSPACE_ACCESS_LEVELS = ["none", "read", "write"];
|
|
@@ -20,13 +20,13 @@ export const ArtifactCreateRequestSchema = z.object({
|
|
|
20
20
|
systemPrompt: z.string().optional(),
|
|
21
21
|
// Snapshotted spinner colors of the chosen Agent Personality (optional).
|
|
22
22
|
spinner: ArtifactSpinnerSchema.optional(),
|
|
23
|
-
// Snapshotted human name of the chosen Agent Personality (optional)
|
|
23
|
+
// Snapshotted human name of the chosen Agent Personality (optional) - shown
|
|
24
24
|
// on the artifact card's identity line as the "who generated it".
|
|
25
25
|
personalityName: z.string().optional(),
|
|
26
26
|
requestId: z.string(),
|
|
27
27
|
});
|
|
28
28
|
// Update edits an artifact's metadata (name/description/project/provider/
|
|
29
|
-
// model/thinking) WITHOUT re-running generation
|
|
29
|
+
// model/thinking) WITHOUT re-running generation - editing never regenerates;
|
|
30
30
|
// the user triggers that separately. Every field except artifactId is
|
|
31
31
|
// optional; only provided fields overwrite.
|
|
32
32
|
export const ArtifactUpdateRequestSchema = z.object({
|
|
@@ -41,7 +41,7 @@ export const ArtifactUpdateRequestSchema = z.object({
|
|
|
41
41
|
requestId: z.string(),
|
|
42
42
|
});
|
|
43
43
|
// Regenerate re-runs generation for an existing artifact using its stored
|
|
44
|
-
// config. It carries no field updates
|
|
44
|
+
// config. It carries no field updates - edit those first via update.request.
|
|
45
45
|
export const ArtifactRegenerateRequestSchema = z.object({
|
|
46
46
|
type: z.literal("artifact.regenerate.request"),
|
|
47
47
|
artifactId: z.string(),
|
|
@@ -166,7 +166,7 @@ export const ArtifactDeletedNotificationSchema = z.object({
|
|
|
166
166
|
artifactId: z.string(),
|
|
167
167
|
}),
|
|
168
168
|
});
|
|
169
|
-
// Input validation helper
|
|
169
|
+
// Input validation helper - extracts CreateArtifactInput from a create request
|
|
170
170
|
export function validateArtifactCreateRequest(data) {
|
|
171
171
|
const result = ArtifactCreateRequestSchema.safeParse(data);
|
|
172
172
|
if (!result.success) {
|
package/dist/artifacts/types.js
CHANGED
|
@@ -27,7 +27,7 @@ export const ArtifactMetadataSchema = z.object({
|
|
|
27
27
|
generationModel: z.string().nullable(),
|
|
28
28
|
// Requested generation mode/effort, persisted so regeneration re-runs with
|
|
29
29
|
// the same settings. Optional: records written before these fields existed
|
|
30
|
-
// omit them (no migrations). The mode is a *request*
|
|
30
|
+
// omit them (no migrations). The mode is a *request* - the artifact service
|
|
31
31
|
// only honors unattended modes and otherwise resolves the provider's
|
|
32
32
|
// unattended default, so generation never stalls on an approval prompt.
|
|
33
33
|
generationModeId: z.string().nullable().optional(),
|
|
@@ -39,7 +39,7 @@ export const ArtifactMetadataSchema = z.object({
|
|
|
39
39
|
generationSpinner: ArtifactSpinnerSchema.nullable().optional(),
|
|
40
40
|
// Human name of the Agent Personality that generated (last generated) this
|
|
41
41
|
// artifact, snapshotted at create/regenerate time like the provider/model
|
|
42
|
-
// above
|
|
42
|
+
// above - the "who actually did it" the card's identity line shows alongside
|
|
43
43
|
// provider/model. Absent ⇒ no personality was used (plain provider/model
|
|
44
44
|
// selection). Purely additive (no daemon floor needed).
|
|
45
45
|
generationPersonalityName: z.string().nullable().optional(),
|
|
@@ -71,7 +71,7 @@ export const ArtifactRunSchema = z.object({
|
|
|
71
71
|
});
|
|
72
72
|
// The full on-disk record: the lean metadata plus its generation run history.
|
|
73
73
|
// `runs` defaults to [] so records written before run history existed parse
|
|
74
|
-
// unchanged (no migrations
|
|
74
|
+
// unchanged (no migrations - same approach the rest of the store takes).
|
|
75
75
|
// list_artifacts / broadcasts keep sending ArtifactMetadata (runs stripped);
|
|
76
76
|
// only inspect_artifact returns this fuller shape.
|
|
77
77
|
export const StoredArtifactSchema = ArtifactMetadataSchema.extend({
|
|
@@ -10,6 +10,7 @@ export const FileBeginMetadataSchema = z.object({
|
|
|
10
10
|
size: z.number().int().nonnegative(),
|
|
11
11
|
encoding: z.enum(["utf-8", "binary"]),
|
|
12
12
|
modifiedAt: z.string(),
|
|
13
|
+
revision: z.string().optional(),
|
|
13
14
|
fileName: z.string().optional(),
|
|
14
15
|
});
|
|
15
16
|
export function encodeFileTransferFrame(input) {
|
|
@@ -418,7 +418,7 @@ export const BrowserAutomationScreenshotElementResultSchema = z.object({
|
|
|
418
418
|
dataBase64: z.string().min(1),
|
|
419
419
|
width: z.number().int().nonnegative(),
|
|
420
420
|
height: z.number().int().nonnegative(),
|
|
421
|
-
/** Render scale used for the clip
|
|
421
|
+
/** Render scale used for the clip - above 1 means the element was re-rendered zoomed in. */
|
|
422
422
|
scale: z.number().positive().optional(),
|
|
423
423
|
});
|
|
424
424
|
export const BrowserAutomationUploadResultSchema = z.object({
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export declare const CLIENT_CAPS: {
|
|
2
|
+
readonly selectiveAgentTimeline: "selective_agent_timeline";
|
|
2
3
|
readonly reasoningMergeEnum: "reasoning_merge_enum";
|
|
3
4
|
readonly customModeIcons: "custom_mode_icons";
|
|
4
5
|
readonly terminalReflowableSnapshot: "terminal_reflowable_snapshot";
|
|
6
|
+
readonly providerSubagents: "provider_subagents";
|
|
7
|
+
readonly projectUpdates: "project_updates";
|
|
5
8
|
readonly browserHost: "browser_host";
|
|
6
9
|
};
|
|
7
10
|
export type ClientCapability = (typeof CLIENT_CAPS)[keyof typeof CLIENT_CAPS];
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export const CLIENT_CAPS = {
|
|
2
|
+
// COMPAT(selectiveAgentTimeline): added in v0.1.106. Capable clients receive
|
|
3
|
+
// agent streams only for their explicit viewed set. Remove after 2027-01-12
|
|
4
|
+
// once the supported client floor is >= v0.1.106.
|
|
5
|
+
selectiveAgentTimeline: "selective_agent_timeline",
|
|
2
6
|
reasoningMergeEnum: "reasoning_merge_enum",
|
|
3
7
|
// COMPAT(customModeIcons): added in v0.1.84. Old clients pin AgentModeIcon to
|
|
4
8
|
// a closed enum and crash rendering unknown values; daemon downgrades icons
|
|
@@ -11,6 +15,11 @@ export const CLIENT_CAPS = {
|
|
|
11
15
|
// Old clients use a strict TerminalState schema and would reject the extra fields.
|
|
12
16
|
// Drop the gate (always send the flags) when floor >= v0.1.88.
|
|
13
17
|
terminalReflowableSnapshot: "terminal_reflowable_snapshot",
|
|
18
|
+
// COMPAT(providerSubagents): added in v0.1.107. The daemon emits provider-owned
|
|
19
|
+
// child descriptors and timelines only to clients that understand the new messages.
|
|
20
|
+
providerSubagents: "provider_subagents",
|
|
21
|
+
// COMPAT(projectUpdates): added in v0.1.109, remove gate after 2027-01-15.
|
|
22
|
+
projectUpdates: "project_updates",
|
|
14
23
|
browserHost: "browser_host",
|
|
15
24
|
};
|
|
16
25
|
//# sourceMappingURL=client-capabilities.js.map
|
|
@@ -32,7 +32,7 @@ export declare function buildRelayWebSocketUrl(params: {
|
|
|
32
32
|
role: RelayRole;
|
|
33
33
|
/**
|
|
34
34
|
* Per-connection routing identifier used by the daemon to open server data sockets.
|
|
35
|
-
* Clients should NOT provide this
|
|
35
|
+
* Clients should NOT provide this - the relay assigns a routing ID on connect.
|
|
36
36
|
*/
|
|
37
37
|
connectionId?: string;
|
|
38
38
|
version?: RelayProtocolVersion | 1 | 2;
|