@harness-gw/sdk 0.4.1 → 0.5.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/README.md CHANGED
@@ -63,7 +63,7 @@ You need a running harness. Hermes is the primary one; see
63
63
  docker run --rm \
64
64
  -v "$PWD/config.yaml:/run/harness-gw/config.yaml:ro" \
65
65
  -v "$PWD/hermes-token:/run/secrets/hermes-token:ro" \
66
- ghcr.io/almogbaku/harness-gw:0.4.1 \
66
+ ghcr.io/almogbaku/harness-gw:0.5.0 \
67
67
  config check --config /run/harness-gw/config.yaml
68
68
  ```
69
69
 
@@ -73,7 +73,7 @@ You need a running harness. Hermes is the primary one; see
73
73
  docker run --rm -p 127.0.0.1:4100:4100 \
74
74
  -v "$PWD/config.yaml:/run/harness-gw/config.yaml:ro" \
75
75
  -v "$PWD/hermes-token:/run/secrets/hermes-token:ro" \
76
- ghcr.io/almogbaku/harness-gw:0.4.1 \
76
+ ghcr.io/almogbaku/harness-gw:0.5.0 \
77
77
  serve --config /run/harness-gw/config.yaml
78
78
  ```
79
79
 
@@ -84,7 +84,8 @@ var AgentSummarySchema = z.strictObject({
84
84
  activity: z.enum(["active", "idle", "unknown"]).optional(),
85
85
  visibility: z.enum(["visible", "hidden"]).optional(),
86
86
  role: z.literal("creator").optional(),
87
- avatar: AgentAvatarSchema2.optional()
87
+ avatar: AgentAvatarSchema2.optional(),
88
+ muted: z.literal(true).optional()
88
89
  });
89
90
  var AgentCatalogEntrySchema2 = z.strictObject({
90
91
  summary: AgentSummarySchema,
@@ -92,6 +93,7 @@ var AgentCatalogEntrySchema2 = z.strictObject({
92
93
  selectable: z.boolean(),
93
94
  editable: z.boolean(),
94
95
  avatarEditable: z.boolean(),
96
+ muteEditable: z.boolean(),
95
97
  revision: IdentifierSchema
96
98
  });
97
99
  var AgentCatalogResponseSchema2 = z.strictObject({
@@ -101,12 +103,13 @@ var AgentCatalogResponseSchema2 = z.strictObject({
101
103
  var AgentUpdateFields2 = {
102
104
  visibility: z.enum(["visible", "hidden"]).optional(),
103
105
  avatar: AgentAvatarSchema2.nullable().optional(),
106
+ muted: z.boolean().optional(),
104
107
  revision: IdentifierSchema
105
108
  };
106
109
  function writesAgentField2(value) {
107
- return value.visibility !== undefined || value.avatar !== undefined;
110
+ return value.visibility !== undefined || value.avatar !== undefined || value.muted !== undefined;
108
111
  }
109
- var AgentUpdateRequestSchema2 = z.strictObject(AgentUpdateFields2).refine(writesAgentField2, "At least one of visibility, avatar");
112
+ var AgentUpdateRequestSchema2 = z.strictObject(AgentUpdateFields2).refine(writesAgentField2, "At least one of visibility, avatar, muted");
110
113
  var AgentUpdateResponseSchema2 = z.strictObject({
111
114
  revision: IdentifierSchema,
112
115
  agent: AgentCatalogEntrySchema2
@@ -842,7 +845,7 @@ var HgwFocusRequestSchema2 = z2.strictObject({
842
845
  idle: z2.boolean().optional()
843
846
  });
844
847
  var HgwAgentsListResponseSchema2 = AgentCatalogResponseSchema2;
845
- var HgwAgentUpdateRequestSchema2 = z2.strictObject({ agentId: IdentifierSchema2, ...AgentUpdateFields2 }).refine(writesAgentField2, "At least one of visibility, avatar");
848
+ var HgwAgentUpdateRequestSchema2 = z2.strictObject({ agentId: IdentifierSchema2, ...AgentUpdateFields2 }).refine(writesAgentField2, "At least one of visibility, avatar, muted");
846
849
  var HgwAgentUpdateResponseSchema2 = AgentUpdateResponseSchema2;
847
850
  var TurnMetaBase = {
848
851
  sequence: SequenceSchema,
@@ -980,10 +983,12 @@ var HgwErrorNotificationSchema2 = readObject({
980
983
  code: z2.string().min(1).max(128),
981
984
  message: z2.string().max(4096)
982
985
  });
986
+ var HGW_REQUEST_TEXT_MAX2 = 200;
983
987
  var ActivityBase = {
984
988
  agentId: IdentifierSchema2,
985
989
  sessionId: IdentifierSchema2,
986
- occurredAt: z2.iso.datetime()
990
+ occurredAt: z2.iso.datetime(),
991
+ replayed: z2.literal(true).optional()
987
992
  };
988
993
  var HgwActivityNotificationSchema2 = z2.discriminatedUnion("type", [
989
994
  readObject({
@@ -995,7 +1000,9 @@ var HgwActivityNotificationSchema2 = z2.discriminatedUnion("type", [
995
1000
  ...ActivityBase,
996
1001
  type: z2.literal("attention-requested"),
997
1002
  requestId: IdentifierSchema2,
998
- attentionKind: z2.enum(["question", "permission"])
1003
+ attentionKind: z2.enum(["question", "permission"]),
1004
+ requestText: z2.string().min(1).max(HGW_REQUEST_TEXT_MAX2).optional(),
1005
+ requestMore: z2.number().int().min(1).optional()
999
1006
  }),
1000
1007
  readObject({
1001
1008
  ...ActivityBase,
@@ -1036,15 +1043,24 @@ var COALESCE_WINDOW_MS2 = {
1036
1043
  failure: 5000,
1037
1044
  completion: 20000
1038
1045
  };
1046
+ var PUSH_TEXT_LIMITS2 = {
1047
+ agentName: 64,
1048
+ sessionTitle: 120,
1049
+ requestText: HGW_REQUEST_TEXT_MAX2
1050
+ };
1051
+ var pushText = (max) => z3.string().min(1).max(max);
1039
1052
  var PushMessageSchema2 = z3.strictObject({
1040
- v: z3.literal(1),
1053
+ v: z3.literal(2),
1041
1054
  category: PushCategorySchema2,
1042
- count: z3.number().int().min(1),
1043
- agentId: IdentifierSchema2.optional(),
1044
- sessionId: IdentifierSchema2.optional(),
1055
+ agentId: IdentifierSchema2,
1056
+ sessionId: IdentifierSchema2,
1045
1057
  occurredAt: z3.iso.datetime(),
1046
- locale: PushLocaleSchema2
1047
- }).refine((message) => message.count === 1 === (message.agentId !== undefined && message.sessionId !== undefined), { message: "A single-Session push carries both ids; a count carries none" });
1058
+ locale: PushLocaleSchema2,
1059
+ agentName: pushText(PUSH_TEXT_LIMITS2.agentName).optional(),
1060
+ sessionTitle: pushText(PUSH_TEXT_LIMITS2.sessionTitle).optional(),
1061
+ requestText: pushText(PUSH_TEXT_LIMITS2.requestText).optional(),
1062
+ requestMore: z3.number().int().min(1).optional()
1063
+ });
1048
1064
  var PushCategoriesSchema2 = z3.strictObject({
1049
1065
  input: z3.boolean(),
1050
1066
  failure: z3.boolean(),
@@ -1164,4 +1180,4 @@ var MCP_APP_SANDBOX_CSP2 = [
1164
1180
  "frame-ancestors 'self'"
1165
1181
  ].join("; ");
1166
1182
 
1167
- export { SESSION_CATALOG_MAX_WINDOW2, RuntimeAuthStateSchema2, OperationCapabilitySchema2, RuntimeInfoSchema2, AgentAvatarSchema2, AgentCatalogEntrySchema2, AgentCatalogResponseSchema2, AgentUpdateFields2, writesAgentField2, AgentUpdateRequestSchema2, AgentUpdateResponseSchema2, SessionStatusSchema2, SessionPlatformSchema2, SessionSchema2, newestSessionFirst2, SessionCatalogResponseSchema2, StopReason2, ToolKind2, ToolLocationSchema2, DiffOperation2, DiffChangeSchema2, ToolDiffSchema2, SessionMessageErrorStatusSchema2, SessionMessageSchema2, SessionPlanActivityMessageSchema2, SessionHistoryResponseSchema2, SessionCreateRequestSchema2, SessionCreateResponseSchema2, SessionPatchRequestSchema2, TurnStopResponseSchema2, TurnSteerRequestSchema2, TurnSteerResponseSchema2, SlashCommandSchema2, MAX_SLASH_COMMANDS2, INTERACTION_PROTOCOL2, SessionWorkspaceCapabilitiesResponseSchema2, GuestRuntimeCapabilitiesResponseSchema2, SessionModelsResponseSchema2, SessionModelUpdateRequestSchema2, SessionModelUpdateResponseSchema2, SessionContextResponseSchema2, ArtifactDescriptorSchema2, SessionTodosResponseSchema2, SessionActivityResponseSchema2, SessionAttachmentStageRequestSchema2, SessionAttachmentStageResponseSchema2, SessionAudioResponseSchema2, SessionTranscriptionRequestSchema2, SessionTranscriptionResponseSchema2, SessionSpeechRequestSchema2, ErrorResponseSchema2, ACP_PROTOCOL_VERSION2, HGW_API_PREFIX2, HGW_ACP_PATH2, HGW_ACP_AGENTS_PATH2, hgwAcpAgentPath2, HGW_META_KEY2, HGW_EXTENSION_VERSION2, HGW_AUTH_METHOD_INVITE2, HGW_ATTACHMENT_URI_SCHEME2, HGW_ARTIFACT_URI_SCHEME2, HGW_METHODS2, HGW_STOP_REASONS2, HGW_PERMISSION_KIND_SESSION2, HGW_PLAN_ID2, HGW_JSONRPC_ERRORS2, IdentifierSchema2, HgwExtensionsSchema2, HgwClientCapabilitiesMetaSchema2, HgwInitializeMetaSchema2, HgwLoginMetaSchema2, HgwSessionNewMetaSchema2, HgwSessionListMetaSchema2, HgwSessionSearchMetaSchema2, HgwSessionSearchResponseSchema2, HgwSessionInfoMetaSchema2, HgwSessionResumeMetaSchema2, HGW_REPLAY_BEFORE2, HgwReplayBeforeSchema2, HgwHistoryCursorSchema2, HgwHistoryPageResponseMetaSchema2, HgwHistoryPageTagSchema2, HgwSessionResumeResponseMetaSchema2, HgwPromptMetaSchema2, HgwSessionUpdateRequestSchema2, HgwSessionPartRequestSchema2, HgwSteerRequestSchema2, HgwSteerResponseSchema2, HgwFocusRequestSchema2, HgwAgentsListResponseSchema2, HgwAgentUpdateRequestSchema2, HgwAgentUpdateResponseSchema2, HgwTurnMetaSchema2, HgwNoticeMetaSchema2, HgwMessageMetaSchema2, HgwCostSchema2, HGW_SUBAGENT_STATUSES2, HgwSubagentSchema2, HgwStateMetaSchema2, HgwChunkMetaSchema2, HgwToolCallMetaSchema2, HgwPlanMetaSchema2, HgwUsageMetaSchema2, HgwAvailableCommandsMetaSchema2, HgwPermissionMetaSchema2, HgwQuestionOptionSchema2, HgwQuestionSchema2, HgwElicitationMetaSchema2, HgwArtifactDescriptorSchema2, formatArtifactUri2, parseArtifactUri2, HgwComposerPrefillNotificationSchema2, HgwErrorNotificationSchema2, HgwActivityNotificationSchema2, PushCategorySchema2, categoryOf2, PushLocaleSchema2, PRESENCE_IDLE_MS2, PRESENCE_HEARTBEAT_MS2, PRESENCE_GRACE_MS2, PRESENCE_CLOSED_GRACE_MS2, COALESCE_WINDOW_MS2, PushMessageSchema2, PushCategoriesSchema2, PushSubscriptionJsonSchema2, PushInfoSchema2, PushRegistrationSchema2, PushUnregistrationSchema2, CallToolResultSchema2, ReadResourceResultSchema2, McpUiCspSchema2, isMcpAppCspDomain2, McpUiPermissionsSchema2, McpAppFilesSchema2, McpAppViewSchema2, viewerFileResult2, McpAppToolCallRequestSchema2, McpAppResourceReadRequestSchema2, MCP_APP_SANDBOX_PATH2, MCP_APP_SANDBOX_CSP2 };
1183
+ export { SESSION_CATALOG_MAX_WINDOW2, RuntimeAuthStateSchema2, OperationCapabilitySchema2, RuntimeInfoSchema2, AgentAvatarSchema2, AgentCatalogEntrySchema2, AgentCatalogResponseSchema2, AgentUpdateFields2, writesAgentField2, AgentUpdateRequestSchema2, AgentUpdateResponseSchema2, SessionStatusSchema2, SessionPlatformSchema2, SessionSchema2, newestSessionFirst2, SessionCatalogResponseSchema2, StopReason2, ToolKind2, ToolLocationSchema2, DiffOperation2, DiffChangeSchema2, ToolDiffSchema2, SessionMessageErrorStatusSchema2, SessionMessageSchema2, SessionPlanActivityMessageSchema2, SessionHistoryResponseSchema2, SessionCreateRequestSchema2, SessionCreateResponseSchema2, SessionPatchRequestSchema2, TurnStopResponseSchema2, TurnSteerRequestSchema2, TurnSteerResponseSchema2, SlashCommandSchema2, MAX_SLASH_COMMANDS2, INTERACTION_PROTOCOL2, SessionWorkspaceCapabilitiesResponseSchema2, GuestRuntimeCapabilitiesResponseSchema2, SessionModelsResponseSchema2, SessionModelUpdateRequestSchema2, SessionModelUpdateResponseSchema2, SessionContextResponseSchema2, ArtifactDescriptorSchema2, SessionTodosResponseSchema2, SessionActivityResponseSchema2, SessionAttachmentStageRequestSchema2, SessionAttachmentStageResponseSchema2, SessionAudioResponseSchema2, SessionTranscriptionRequestSchema2, SessionTranscriptionResponseSchema2, SessionSpeechRequestSchema2, ErrorResponseSchema2, ACP_PROTOCOL_VERSION2, HGW_API_PREFIX2, HGW_ACP_PATH2, HGW_ACP_AGENTS_PATH2, hgwAcpAgentPath2, HGW_META_KEY2, HGW_EXTENSION_VERSION2, HGW_AUTH_METHOD_INVITE2, HGW_ATTACHMENT_URI_SCHEME2, HGW_ARTIFACT_URI_SCHEME2, HGW_METHODS2, HGW_STOP_REASONS2, HGW_PERMISSION_KIND_SESSION2, HGW_PLAN_ID2, HGW_JSONRPC_ERRORS2, IdentifierSchema2, HgwExtensionsSchema2, HgwClientCapabilitiesMetaSchema2, HgwInitializeMetaSchema2, HgwLoginMetaSchema2, HgwSessionNewMetaSchema2, HgwSessionListMetaSchema2, HgwSessionSearchMetaSchema2, HgwSessionSearchResponseSchema2, HgwSessionInfoMetaSchema2, HgwSessionResumeMetaSchema2, HGW_REPLAY_BEFORE2, HgwReplayBeforeSchema2, HgwHistoryCursorSchema2, HgwHistoryPageResponseMetaSchema2, HgwHistoryPageTagSchema2, HgwSessionResumeResponseMetaSchema2, HgwPromptMetaSchema2, HgwSessionUpdateRequestSchema2, HgwSessionPartRequestSchema2, HgwSteerRequestSchema2, HgwSteerResponseSchema2, HgwFocusRequestSchema2, HgwAgentsListResponseSchema2, HgwAgentUpdateRequestSchema2, HgwAgentUpdateResponseSchema2, HgwTurnMetaSchema2, HgwNoticeMetaSchema2, HgwMessageMetaSchema2, HgwCostSchema2, HGW_SUBAGENT_STATUSES2, HgwSubagentSchema2, HgwStateMetaSchema2, HgwChunkMetaSchema2, HgwToolCallMetaSchema2, HgwPlanMetaSchema2, HgwUsageMetaSchema2, HgwAvailableCommandsMetaSchema2, HgwPermissionMetaSchema2, HgwQuestionOptionSchema2, HgwQuestionSchema2, HgwElicitationMetaSchema2, HgwArtifactDescriptorSchema2, formatArtifactUri2, parseArtifactUri2, HgwComposerPrefillNotificationSchema2, HgwErrorNotificationSchema2, HGW_REQUEST_TEXT_MAX2, HgwActivityNotificationSchema2, PushCategorySchema2, categoryOf2, PushLocaleSchema2, PRESENCE_IDLE_MS2, PRESENCE_HEARTBEAT_MS2, PRESENCE_GRACE_MS2, PRESENCE_CLOSED_GRACE_MS2, COALESCE_WINDOW_MS2, PUSH_TEXT_LIMITS2, PushMessageSchema2, PushCategoriesSchema2, PushSubscriptionJsonSchema2, PushInfoSchema2, PushRegistrationSchema2, PushUnregistrationSchema2, CallToolResultSchema2, ReadResourceResultSchema2, McpUiCspSchema2, isMcpAppCspDomain2, McpUiPermissionsSchema2, McpAppFilesSchema2, McpAppViewSchema2, viewerFileResult2, McpAppToolCallRequestSchema2, McpAppResourceReadRequestSchema2, MCP_APP_SANDBOX_PATH2, MCP_APP_SANDBOX_CSP2 };
@@ -17,6 +17,13 @@ export type AcpSessionStoreOptions = {
17
17
  export declare function createAcpSessionStore({ connection, now, onTurnFinished, }: AcpSessionStoreOptions): {
18
18
  subscribe: (sessionId: string, agentId?: string) => () => void;
19
19
  dispose(): void;
20
+ /**
21
+ * A connection that starts over re-sends every request still open as it
22
+ * catches up, so one the old connection left open and the new one does
23
+ * not name was settled while nobody was listening; and what it re-sends
24
+ * is no longer marked as already seen.
25
+ */
26
+ startOver(): void;
20
27
  put: (sessionId: string, info: HgwSessionInfoMeta, updatedAt?: string | null) => void;
21
28
  rowsFor: (sessionIds: Iterable<string>) => {
22
29
  sessionId: string;
@@ -28,6 +28,7 @@ export declare function createAcpWorkspaceClient({ connection, rest, agentIdFor,
28
28
  visibility?: "visible" | "hidden" | undefined;
29
29
  role?: "creator" | undefined;
30
30
  avatar?: string | undefined;
31
+ muted?: true | undefined;
31
32
  }[]>;
32
33
  refreshAgents(): Promise<{
33
34
  kind: "ready";
@@ -39,6 +40,7 @@ export declare function createAcpWorkspaceClient({ connection, rest, agentIdFor,
39
40
  visibility?: "visible" | "hidden" | undefined;
40
41
  role?: "creator" | undefined;
41
42
  avatar?: string | undefined;
43
+ muted?: true | undefined;
42
44
  }[]>;
43
45
  listAgentCatalog(): Promise<{
44
46
  summary: {
@@ -51,11 +53,13 @@ export declare function createAcpWorkspaceClient({ connection, rest, agentIdFor,
51
53
  visibility?: "visible" | "hidden" | undefined;
52
54
  role?: "creator" | undefined;
53
55
  avatar?: string | undefined;
56
+ muted?: true | undefined;
54
57
  };
55
58
  visibility: "visible" | "hidden";
56
59
  selectable: boolean;
57
60
  editable: boolean;
58
61
  avatarEditable: boolean;
62
+ muteEditable: boolean;
59
63
  }[]>;
60
64
  updateAgent: (agentId: string, patch: AgentUpdate) => Promise<void>;
61
65
  subscribeAgentCatalog: (listener: () => void) => () => void;
@@ -1518,8 +1518,15 @@ function statusFromState(update) {
1518
1518
  const stopReason = update.stopReason;
1519
1519
  return stopReason === HGW_STOP_REASONS2.error || stopReason === HGW_STOP_REASONS2.uncertain ? "failed" : "idle";
1520
1520
  }
1521
- function activityEventOf(notification) {
1522
- const { agentId, sessionId, occurredAt, type } = notification;
1521
+ var FEED_STATUS = {
1522
+ "turn-started": "running",
1523
+ "attention-requested": "waiting-for-input",
1524
+ "attention-resolved": "running",
1525
+ "turn-finished": "idle",
1526
+ "turn-failed": "failed"
1527
+ };
1528
+ function activityEventOf(notification, marksReplays) {
1529
+ const { agentId, sessionId, occurredAt, type, replayed } = notification;
1523
1530
  if (type === "unread-changed")
1524
1531
  return;
1525
1532
  const key = "turnId" in notification ? notification.turnId : ("requestId" in notification) ? notification.requestId : occurredAt;
@@ -1527,15 +1534,20 @@ function activityEventOf(notification) {
1527
1534
  id: `${sessionId}:${key}:${type}`,
1528
1535
  agentId,
1529
1536
  sessionId,
1530
- occurredAt
1537
+ occurredAt,
1538
+ ...replayed && marksReplays ? { replayed } : {}
1531
1539
  };
1532
- if (type === "attention-requested")
1540
+ if (type === "attention-requested") {
1541
+ const { requestText, requestMore } = notification;
1533
1542
  return {
1534
1543
  ...base,
1535
1544
  type,
1536
1545
  requestId: notification.requestId,
1537
- attentionKind: notification.attentionKind
1546
+ attentionKind: notification.attentionKind,
1547
+ ...requestText === undefined ? {} : { requestText },
1548
+ ...requestMore === undefined ? {} : { requestMore }
1538
1549
  };
1550
+ }
1539
1551
  if (type === "attention-resolved")
1540
1552
  return { ...base, type, requestId: notification.requestId };
1541
1553
  return { ...base, type, turnId: notification.turnId };
@@ -1553,6 +1565,9 @@ function createAcpSessionStore({
1553
1565
  const todos = new Map;
1554
1566
  const replaying = new Map;
1555
1567
  const subscriptions = new Set;
1568
+ const subscribed = new Map;
1569
+ const openRequests = new Map;
1570
+ let marksReplays = true;
1556
1571
  const todoListeners = new Map;
1557
1572
  const activityListeners = new Set;
1558
1573
  const invalidationListeners = new Map;
@@ -1660,16 +1675,43 @@ function createAcpSessionStore({
1660
1675
  update: (update, meta) => acceptUpdate(sessionId, update, meta),
1661
1676
  replay: () => holdReplayedStatus(sessionId)
1662
1677
  });
1678
+ subscribed.set(sessionId, (subscribed.get(sessionId) ?? 0) + 1);
1663
1679
  return () => {
1664
1680
  leave();
1681
+ const holders = (subscribed.get(sessionId) ?? 1) - 1;
1682
+ if (holders > 0)
1683
+ subscribed.set(sessionId, holders);
1684
+ else
1685
+ subscribed.delete(sessionId);
1665
1686
  todos.delete(sessionId);
1666
1687
  replaying.delete(sessionId);
1667
1688
  };
1668
1689
  }
1690
+ function noteActivity(notification) {
1691
+ const { sessionId, type } = notification;
1692
+ const open = openRequests.get(sessionId) ?? new Set;
1693
+ if (type === "attention-requested")
1694
+ open.add(notification.requestId);
1695
+ else if (type === "attention-resolved")
1696
+ open.delete(notification.requestId);
1697
+ else if (type === "turn-finished" || type === "turn-failed")
1698
+ open.clear();
1699
+ if (open.size > 0)
1700
+ openRequests.set(sessionId, open);
1701
+ else
1702
+ openRequests.delete(sessionId);
1703
+ const status = FEED_STATUS[type];
1704
+ if (!status || subscribed.has(sessionId))
1705
+ return;
1706
+ if (type === "attention-resolved" && open.size > 0)
1707
+ return;
1708
+ patch(sessionId, { status });
1709
+ }
1669
1710
  const leaveActivity = subscribeHgwNotification(connection, HGW_METHODS2.notify.activity, HgwActivityNotificationSchema2, (notification) => {
1670
1711
  if (notification.type === "unread-changed")
1671
1712
  return patch(notification.sessionId, { unread: notification.unread });
1672
- const event = activityEventOf(notification);
1713
+ noteActivity(notification);
1714
+ const event = activityEventOf(notification, marksReplays);
1673
1715
  if (event)
1674
1716
  emitActivity(event);
1675
1717
  });
@@ -1678,6 +1720,10 @@ function createAcpSessionStore({
1678
1720
  dispose() {
1679
1721
  leaveActivity();
1680
1722
  },
1723
+ startOver() {
1724
+ openRequests.clear();
1725
+ marksReplays = false;
1726
+ },
1681
1727
  put,
1682
1728
  rowsFor,
1683
1729
  setTitle: (sessionId, title) => titles.set(sessionId, title),
@@ -1922,8 +1968,10 @@ function createAcpWorkspaceClient({
1922
1968
  let connectionCurrentlyReady = connectionEverReady;
1923
1969
  const leaveStatus = connection.subscribeStatus((status) => {
1924
1970
  if (status === "ready") {
1925
- if (connectionEverReady && !connectionCurrentlyReady)
1971
+ if (connectionEverReady && !connectionCurrentlyReady) {
1972
+ store.startOver();
1926
1973
  scheduleSessionRelist();
1974
+ }
1927
1975
  connectionEverReady = true;
1928
1976
  connectionCurrentlyReady = true;
1929
1977
  } else {
@@ -1971,12 +2019,20 @@ function createAcpWorkspaceClient({
1971
2019
  return (await catalog()).agents.map(({ summary }) => summary);
1972
2020
  },
1973
2021
  async listAgentCatalog() {
1974
- return (await catalog()).agents.map(({ summary, visibility, selectable, editable, avatarEditable }) => ({
2022
+ return (await catalog()).agents.map(({
2023
+ summary,
2024
+ visibility,
2025
+ selectable,
2026
+ editable,
2027
+ avatarEditable,
2028
+ muteEditable
2029
+ }) => ({
1975
2030
  summary,
1976
2031
  visibility,
1977
2032
  selectable,
1978
2033
  editable,
1979
- avatarEditable
2034
+ avatarEditable,
2035
+ muteEditable
1980
2036
  }));
1981
2037
  },
1982
2038
  updateAgent,
@@ -9,6 +9,8 @@ export type AgentVisibility = "visible" | "hidden";
9
9
  export type AgentUpdate = {
10
10
  visibility?: AgentVisibility;
11
11
  avatar?: string | null;
12
+ /** Mutes the Agent's notifications, or with `false` unmutes them. */
13
+ muted?: boolean;
12
14
  };
13
15
  /** Actionable Agent update refusals; all other failures remain ordinary Errors. */
14
16
  export declare class AgentUpdateError extends Error {
@@ -21,6 +23,8 @@ export type ActivityBase = {
21
23
  agentId: string;
22
24
  sessionId: string;
23
25
  occurredAt: string;
26
+ /** Re-sent on connect from what the gateway already held. */
27
+ replayed?: true;
24
28
  };
25
29
  export type WorkspaceActivityEvent = (ActivityBase & {
26
30
  type: "turn-started";
@@ -32,6 +36,10 @@ export type WorkspaceActivityEvent = (ActivityBase & {
32
36
  type: "attention-requested";
33
37
  attentionKind: "question" | "permission";
34
38
  requestId: string;
39
+ /** One masked line of what is asked; absent when nothing can be shown. */
40
+ requestText?: string;
41
+ /** How many further questions the request asks. */
42
+ requestMore?: number;
35
43
  }) | (ActivityBase & {
36
44
  type: "attention-resolved";
37
45
  requestId: string;
@@ -335,6 +335,7 @@ export declare const HgwAgentsListResponseSchema: z.ZodObject<{
335
335
  }>>;
336
336
  role: z.ZodOptional<z.ZodLiteral<"creator">>;
337
337
  avatar: z.ZodOptional<z.ZodString>;
338
+ muted: z.ZodOptional<z.ZodLiteral<true>>;
338
339
  }, z.core.$strict>;
339
340
  visibility: z.ZodEnum<{
340
341
  visible: "visible";
@@ -343,16 +344,18 @@ export declare const HgwAgentsListResponseSchema: z.ZodObject<{
343
344
  selectable: z.ZodBoolean;
344
345
  editable: z.ZodBoolean;
345
346
  avatarEditable: z.ZodBoolean;
347
+ muteEditable: z.ZodBoolean;
346
348
  revision: z.ZodString;
347
349
  }, z.core.$strict>>;
348
350
  }, z.core.$strict>;
349
- /** `_hgw/agents/update` params: at least one of visibility and avatar. */
351
+ /** `_hgw/agents/update` params: at least one of visibility, avatar, and muted. */
350
352
  export declare const HgwAgentUpdateRequestSchema: z.ZodObject<{
351
353
  visibility: z.ZodOptional<z.ZodEnum<{
352
354
  visible: "visible";
353
355
  hidden: "hidden";
354
356
  }>>;
355
357
  avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
358
+ muted: z.ZodOptional<z.ZodBoolean>;
356
359
  revision: z.ZodString;
357
360
  agentId: z.ZodString;
358
361
  }, z.core.$strict>;
@@ -383,6 +386,7 @@ export declare const HgwAgentUpdateResponseSchema: z.ZodObject<{
383
386
  }>>;
384
387
  role: z.ZodOptional<z.ZodLiteral<"creator">>;
385
388
  avatar: z.ZodOptional<z.ZodString>;
389
+ muted: z.ZodOptional<z.ZodLiteral<true>>;
386
390
  }, z.core.$strict>;
387
391
  visibility: z.ZodEnum<{
388
392
  visible: "visible";
@@ -391,6 +395,7 @@ export declare const HgwAgentUpdateResponseSchema: z.ZodObject<{
391
395
  selectable: z.ZodBoolean;
392
396
  editable: z.ZodBoolean;
393
397
  avatarEditable: z.ZodBoolean;
398
+ muteEditable: z.ZodBoolean;
394
399
  revision: z.ZodString;
395
400
  }, z.core.$strict>;
396
401
  }, z.core.$strict>;
@@ -803,9 +808,16 @@ export declare const HgwErrorNotificationSchema: z.ZodObject<{
803
808
  message: z.ZodString;
804
809
  }, z.core.$strip>;
805
810
  /**
806
- * `_hgw/activity`: content-free workspace events for every Session the
807
- * connection may observe. Hydrated on connect from coordinator snapshots and
808
- * the session list.
811
+ * The longest a request preview may be, in UTF-16 units, as zod's `.max`
812
+ * counts; the push payload's `requestText` shares it.
813
+ */
814
+ export declare const HGW_REQUEST_TEXT_MAX = 200;
815
+ /**
816
+ * `_hgw/activity`: workspace events for every Session the connection may
817
+ * observe, in ids, times, and kinds. An attention request also carries a
818
+ * one-line preview of what it asks, with credentials masked, and how many
819
+ * questions follow it. Hydrated on connect from coordinator snapshots and the
820
+ * session list, and those items are marked `replayed`.
809
821
  */
810
822
  export declare const HgwActivityNotificationSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
811
823
  type: z.ZodEnum<{
@@ -817,6 +829,7 @@ export declare const HgwActivityNotificationSchema: z.ZodDiscriminatedUnion<[z.Z
817
829
  agentId: z.ZodString;
818
830
  sessionId: z.ZodString;
819
831
  occurredAt: z.ZodISODateTime;
832
+ replayed: z.ZodOptional<z.ZodLiteral<true>>;
820
833
  }, z.core.$strip>, z.ZodObject<{
821
834
  type: z.ZodLiteral<"attention-requested">;
822
835
  requestId: z.ZodString;
@@ -824,20 +837,25 @@ export declare const HgwActivityNotificationSchema: z.ZodDiscriminatedUnion<[z.Z
824
837
  question: "question";
825
838
  permission: "permission";
826
839
  }>;
840
+ requestText: z.ZodOptional<z.ZodString>;
841
+ requestMore: z.ZodOptional<z.ZodNumber>;
827
842
  agentId: z.ZodString;
828
843
  sessionId: z.ZodString;
829
844
  occurredAt: z.ZodISODateTime;
845
+ replayed: z.ZodOptional<z.ZodLiteral<true>>;
830
846
  }, z.core.$strip>, z.ZodObject<{
831
847
  type: z.ZodLiteral<"attention-resolved">;
832
848
  requestId: z.ZodString;
833
849
  agentId: z.ZodString;
834
850
  sessionId: z.ZodString;
835
851
  occurredAt: z.ZodISODateTime;
852
+ replayed: z.ZodOptional<z.ZodLiteral<true>>;
836
853
  }, z.core.$strip>, z.ZodObject<{
837
854
  type: z.ZodLiteral<"unread-changed">;
838
855
  unread: z.ZodBoolean;
839
856
  agentId: z.ZodString;
840
857
  sessionId: z.ZodString;
841
858
  occurredAt: z.ZodISODateTime;
859
+ replayed: z.ZodOptional<z.ZodLiteral<true>>;
842
860
  }, z.core.$strip>], "type">;
843
861
  export type HgwActivityNotification = z.infer<typeof HgwActivityNotificationSchema>;
@@ -166,6 +166,7 @@ export declare const AgentCatalogEntrySchema: z.ZodObject<{
166
166
  }>>;
167
167
  role: z.ZodOptional<z.ZodLiteral<"creator">>;
168
168
  avatar: z.ZodOptional<z.ZodString>;
169
+ muted: z.ZodOptional<z.ZodLiteral<true>>;
169
170
  }, z.core.$strict>;
170
171
  visibility: z.ZodEnum<{
171
172
  visible: "visible";
@@ -174,6 +175,7 @@ export declare const AgentCatalogEntrySchema: z.ZodObject<{
174
175
  selectable: z.ZodBoolean;
175
176
  editable: z.ZodBoolean;
176
177
  avatarEditable: z.ZodBoolean;
178
+ muteEditable: z.ZodBoolean;
177
179
  revision: z.ZodString;
178
180
  }, z.core.$strict>;
179
181
  export type AgentCatalogEntry = z.infer<typeof AgentCatalogEntrySchema>;
@@ -203,6 +205,7 @@ export declare const AgentCatalogResponseSchema: z.ZodObject<{
203
205
  }>>;
204
206
  role: z.ZodOptional<z.ZodLiteral<"creator">>;
205
207
  avatar: z.ZodOptional<z.ZodString>;
208
+ muted: z.ZodOptional<z.ZodLiteral<true>>;
206
209
  }, z.core.$strict>;
207
210
  visibility: z.ZodEnum<{
208
211
  visible: "visible";
@@ -211,6 +214,7 @@ export declare const AgentCatalogResponseSchema: z.ZodObject<{
211
214
  selectable: z.ZodBoolean;
212
215
  editable: z.ZodBoolean;
213
216
  avatarEditable: z.ZodBoolean;
217
+ muteEditable: z.ZodBoolean;
214
218
  revision: z.ZodString;
215
219
  }, z.core.$strict>>;
216
220
  }, z.core.$strict>;
@@ -222,12 +226,15 @@ export declare const AgentUpdateFields: {
222
226
  hidden: "hidden";
223
227
  }>>;
224
228
  avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
229
+ /** Mutes the Agent's notifications, or with `false` unmutes them. */
230
+ muted: z.ZodOptional<z.ZodBoolean>;
225
231
  revision: z.ZodString;
226
232
  };
227
233
  /** At least one field besides the revision. */
228
234
  export declare function writesAgentField(value: {
229
235
  visibility?: unknown;
230
236
  avatar?: unknown;
237
+ muted?: unknown;
231
238
  }): boolean;
232
239
  export declare const AgentUpdateRequestSchema: z.ZodObject<{
233
240
  visibility: z.ZodOptional<z.ZodEnum<{
@@ -235,6 +242,7 @@ export declare const AgentUpdateRequestSchema: z.ZodObject<{
235
242
  hidden: "hidden";
236
243
  }>>;
237
244
  avatar: z.ZodOptional<z.ZodNullable<z.ZodString>>;
245
+ muted: z.ZodOptional<z.ZodBoolean>;
238
246
  revision: z.ZodString;
239
247
  }, z.core.$strict>;
240
248
  export type AgentUpdateRequest = z.infer<typeof AgentUpdateRequestSchema>;
@@ -266,6 +274,7 @@ export declare const AgentUpdateResponseSchema: z.ZodObject<{
266
274
  }>>;
267
275
  role: z.ZodOptional<z.ZodLiteral<"creator">>;
268
276
  avatar: z.ZodOptional<z.ZodString>;
277
+ muted: z.ZodOptional<z.ZodLiteral<true>>;
269
278
  }, z.core.$strict>;
270
279
  visibility: z.ZodEnum<{
271
280
  visible: "visible";
@@ -274,6 +283,7 @@ export declare const AgentUpdateResponseSchema: z.ZodObject<{
274
283
  selectable: z.ZodBoolean;
275
284
  editable: z.ZodBoolean;
276
285
  avatarEditable: z.ZodBoolean;
286
+ muteEditable: z.ZodBoolean;
277
287
  revision: z.ZodString;
278
288
  }, z.core.$strict>;
279
289
  }, z.core.$strict>;
@@ -1,8 +1,12 @@
1
1
  import { z } from "zod";
2
2
  /**
3
3
  * Web Push contract shared by the browser, the service worker, and the gateway.
4
- * Content-free by construction: a category, a count, opaque ids when exactly
5
- * one Session is meant, a timestamp, and the device locale.
4
+ * One message is about one Session. It always carries the category, the Agent
5
+ * and Session ids, when the Session's newest event happened, and the device
6
+ * locale. A device whose registration is under 30 days old may also get the
7
+ * Agent's name, the Session's title, and a preview of what is asked: each one
8
+ * line, cut to its `PUSH_TEXT_LIMITS` entry, with credentials masked. Every
9
+ * encrypted message is padded to one size.
6
10
  */
7
11
  export declare const PushCategorySchema: z.ZodEnum<{
8
12
  input: "input";
@@ -31,24 +35,40 @@ export declare const PRESENCE_GRACE_MS = 60000;
31
35
  * operator who really left is owed, inside a 3-second input window.
32
36
  */
33
37
  export declare const PRESENCE_CLOSED_GRACE_MS = 2000;
34
- /** Fixed window from the first event in which one push per category is sent. */
38
+ /**
39
+ * Fixed window from a category's first event. When it closes, each Session
40
+ * that had an event inside it gets one push, about its newest one.
41
+ */
35
42
  export declare const COALESCE_WINDOW_MS: Readonly<Record<PushCategory, number>>;
36
- /** The encrypted payload a device receives; ids are present iff count is 1. */
43
+ /** The longest each text field may be, in UTF-16 units, as zod's `.max` counts. */
44
+ export declare const PUSH_TEXT_LIMITS: {
45
+ readonly agentName: 64;
46
+ readonly sessionTitle: 120;
47
+ readonly requestText: 200;
48
+ };
49
+ /**
50
+ * The encrypted payload a device receives. `v` versions it on its own, apart
51
+ * from the ACP extension version; `requestMore` counts the questions asked
52
+ * after the one `requestText` previews.
53
+ */
37
54
  export declare const PushMessageSchema: z.ZodObject<{
38
- v: z.ZodLiteral<1>;
55
+ v: z.ZodLiteral<2>;
39
56
  category: z.ZodEnum<{
40
57
  input: "input";
41
58
  failure: "failure";
42
59
  completion: "completion";
43
60
  }>;
44
- count: z.ZodNumber;
45
- agentId: z.ZodOptional<z.ZodString>;
46
- sessionId: z.ZodOptional<z.ZodString>;
61
+ agentId: z.ZodString;
62
+ sessionId: z.ZodString;
47
63
  occurredAt: z.ZodISODateTime;
48
64
  locale: z.ZodEnum<{
49
65
  en: "en";
50
66
  he: "he";
51
67
  }>;
68
+ agentName: z.ZodOptional<z.ZodString>;
69
+ sessionTitle: z.ZodOptional<z.ZodString>;
70
+ requestText: z.ZodOptional<z.ZodString>;
71
+ requestMore: z.ZodOptional<z.ZodNumber>;
52
72
  }, z.core.$strict>;
53
73
  export type PushMessage = z.infer<typeof PushMessageSchema>;
54
74
  export declare const PushCategoriesSchema: z.ZodObject<{
@@ -112,6 +112,7 @@ import {
112
112
  parseArtifactUri2,
113
113
  HgwComposerPrefillNotificationSchema2,
114
114
  HgwErrorNotificationSchema2,
115
+ HGW_REQUEST_TEXT_MAX2,
115
116
  HgwActivityNotificationSchema2,
116
117
  PushCategorySchema2,
117
118
  categoryOf2,
@@ -121,6 +122,7 @@ import {
121
122
  PRESENCE_GRACE_MS2,
122
123
  PRESENCE_CLOSED_GRACE_MS2,
123
124
  COALESCE_WINDOW_MS2,
125
+ PUSH_TEXT_LIMITS2,
124
126
  PushMessageSchema2,
125
127
  PushCategoriesSchema2,
126
128
  PushSubscriptionJsonSchema2,
@@ -218,6 +220,7 @@ export {
218
220
  HGW_PERMISSION_KIND_SESSION2 as HGW_PERMISSION_KIND_SESSION,
219
221
  HGW_PLAN_ID2 as HGW_PLAN_ID,
220
222
  HGW_REPLAY_BEFORE2 as HGW_REPLAY_BEFORE,
223
+ HGW_REQUEST_TEXT_MAX2 as HGW_REQUEST_TEXT_MAX,
221
224
  HGW_STOP_REASONS2 as HGW_STOP_REASONS,
222
225
  HGW_SUBAGENT_STATUSES2 as HGW_SUBAGENT_STATUSES,
223
226
  HgwActivityNotificationSchema2 as HgwActivityNotificationSchema,
@@ -283,6 +286,7 @@ export {
283
286
  PRESENCE_GRACE_MS2 as PRESENCE_GRACE_MS,
284
287
  PRESENCE_HEARTBEAT_MS2 as PRESENCE_HEARTBEAT_MS,
285
288
  PRESENCE_IDLE_MS2 as PRESENCE_IDLE_MS,
289
+ PUSH_TEXT_LIMITS2 as PUSH_TEXT_LIMITS,
286
290
  PushCategoriesSchema2 as PushCategoriesSchema,
287
291
  PushCategorySchema2 as PushCategorySchema,
288
292
  PushInfoSchema2 as PushInfoSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-gw/sdk",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "A gateway that puts Hermes, OpenClaw, and OpenCode behind one ACP WebSocket, and the browser client and protocol SDK for it.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -56,6 +56,7 @@
56
56
  "@openclaw/gateway-client": "2026.10.2",
57
57
  "@openclaw/gateway-protocol": "2026.10.2",
58
58
  "@opencode-ai/sdk": "1.19.0",
59
+ "@sanity-labs/secret-scan": "1.1.0",
59
60
  "@types/bun": "^1.4.3",
60
61
  "@types/ms": "2.1.0",
61
62
  "@types/node": "^26",