@pellux/goodvibes-sdk 0.25.1 → 0.25.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/dist/_internal/daemon/otlp-protobuf.d.ts +3 -0
- package/dist/_internal/daemon/otlp-protobuf.d.ts.map +1 -0
- package/dist/_internal/daemon/otlp-protobuf.js +968 -0
- package/dist/_internal/daemon/telemetry-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/telemetry-routes.js +22 -13
- package/dist/_internal/platform/adapters/ntfy/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/ntfy/index.js +93 -0
- package/dist/_internal/platform/adapters/types.d.ts +21 -0
- package/dist/_internal/platform/adapters/types.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/setup-schema.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/setup-schema.js +4 -3
- package/dist/_internal/platform/channels/delivery/strategies-core.d.ts.map +1 -1
- package/dist/_internal/platform/channels/delivery/strategies-core.js +1 -0
- package/dist/_internal/platform/channels/provider-runtime.d.ts +1 -1
- package/dist/_internal/platform/channels/provider-runtime.d.ts.map +1 -1
- package/dist/_internal/platform/channels/provider-runtime.js +14 -9
- package/dist/_internal/platform/channels/reply-pipeline.d.ts +1 -0
- package/dist/_internal/platform/channels/reply-pipeline.d.ts.map +1 -1
- package/dist/_internal/platform/channels/reply-pipeline.js +32 -1
- package/dist/_internal/platform/companion/companion-chat-manager.d.ts +12 -0
- package/dist/_internal/platform/companion/companion-chat-manager.d.ts.map +1 -1
- package/dist/_internal/platform/companion/companion-chat-manager.js +41 -0
- package/dist/_internal/platform/config/schema-domain-surfaces.js +1 -1
- package/dist/_internal/platform/control-plane/conversation-message.d.ts +1 -1
- package/dist/_internal/platform/control-plane/conversation-message.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade-composition.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade-composition.js +3 -0
- package/dist/_internal/platform/daemon/surface-actions.d.ts +21 -1
- package/dist/_internal/platform/daemon/surface-actions.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/surface-actions.js +184 -0
- package/dist/_internal/platform/daemon/surface-delivery.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/surface-delivery.js +2 -0
- package/dist/_internal/platform/integrations/index.d.ts +1 -1
- package/dist/_internal/platform/integrations/index.d.ts.map +1 -1
- package/dist/_internal/platform/integrations/index.js +1 -1
- package/dist/_internal/platform/integrations/ntfy.d.ts +11 -0
- package/dist/_internal/platform/integrations/ntfy.d.ts.map +1 -1
- package/dist/_internal/platform/integrations/ntfy.js +266 -30
- package/dist/_internal/platform/providers/registry.d.ts +1 -0
- package/dist/_internal/platform/providers/registry.d.ts.map +1 -1
- package/dist/_internal/platform/providers/registry.js +15 -5
- package/dist/_internal/platform/runtime/emitters/agents.d.ts +3 -0
- package/dist/_internal/platform/runtime/emitters/agents.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/events/agents.d.ts +3 -0
- package/dist/_internal/platform/runtime/events/agents.d.ts.map +1 -1
- package/dist/_internal/platform/tools/agent/manager.d.ts.map +1 -1
- package/dist/_internal/platform/tools/agent/manager.js +3 -0
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
- package/dist/_internal/platform/runtime/contracts/index.d.ts +0 -40
- package/dist/_internal/platform/runtime/contracts/index.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/index.js +0 -133
- package/dist/_internal/platform/runtime/contracts/migrations/index.d.ts +0 -75
- package/dist/_internal/platform/runtime/contracts/migrations/index.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/migrations/index.js +0 -158
- package/dist/_internal/platform/runtime/contracts/migrations/schemas.d.ts +0 -57
- package/dist/_internal/platform/runtime/contracts/migrations/schemas.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/migrations/schemas.js +0 -157
- package/dist/_internal/platform/runtime/contracts/types.d.ts +0 -123
- package/dist/_internal/platform/runtime/contracts/types.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/types.js +0 -41
- package/dist/_internal/platform/runtime/contracts/validators/event-envelope.d.ts +0 -24
- package/dist/_internal/platform/runtime/contracts/validators/event-envelope.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/validators/event-envelope.js +0 -104
- package/dist/_internal/platform/runtime/contracts/validators/index.d.ts +0 -11
- package/dist/_internal/platform/runtime/contracts/validators/index.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/validators/index.js +0 -10
- package/dist/_internal/platform/runtime/contracts/validators/runtime-state.d.ts +0 -23
- package/dist/_internal/platform/runtime/contracts/validators/runtime-state.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/validators/runtime-state.js +0 -101
- package/dist/_internal/platform/runtime/contracts/validators/session.d.ts +0 -24
- package/dist/_internal/platform/runtime/contracts/validators/session.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/validators/session.js +0 -103
- package/dist/_internal/platform/runtime/contracts/version.d.ts +0 -84
- package/dist/_internal/platform/runtime/contracts/version.d.ts.map +0 -1
- package/dist/_internal/platform/runtime/contracts/version.js +0 -41
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telemetry-routes.d.ts","sourceRoot":"","sources":["../../../src/_internal/daemon/telemetry-routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAyB,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"telemetry-routes.d.ts","sourceRoot":"","sources":["../../../src/_internal/daemon/telemetry-routes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAyB,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAEtF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,KAAK,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAC7D,KAAK,iBAAiB,GAAG,MAAM,GAAG,KAAK,CAAC;AAExC,UAAU,eAAe;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAC;CACnC;AAED,UAAU,gBAAgB;IACxB,WAAW,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,iBAAiB,EAAE,aAAa,EAAE,OAAO,GAAG;QACrF,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;QACjC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;QAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;QAC1B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;QACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;KAC9B,CAAC;IACF,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,iBAAiB,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC;IACjG,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,iBAAiB,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC;IACjG,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,iBAAiB,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC;IAChG,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,iBAAiB,EAAE,aAAa,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC/G,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAClF,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC;IAChF,uBAAuB,IAAI,OAAO,CAAC;CACpC;AAED;;;;GAIG;AACH,UAAU,mBAAmB;IAC3B,2EAA2E;IAC3E,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACnD,4EAA4E;IAC5E,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACrD,qFAAqF;IACrF,aAAa,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACvD;AAED,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,6BAA6B,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,sBAAsB,GAAG,IAAI,CAAC;IACxF;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACjD;AAsND,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,qBAAqB,GAC7B,IAAI,CACL,sBAAsB,EACpB,sBAAsB,GACtB,oBAAoB,GACpB,oBAAoB,GACpB,oBAAoB,GACpB,qBAAqB,GACrB,4BAA4B,GAC5B,wBAAwB,GACxB,sBAAsB,GACtB,yBAAyB,GACzB,uBAAuB,GACvB,yBAAyB,GACzB,0BAA0B,CAC7B,CA2IA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { buildMissingScopeBody } from './http-policy.js';
|
|
2
|
+
import { decodeOtlpProtobuf } from './otlp-protobuf.js';
|
|
2
3
|
import { DaemonErrorCategory } from '../errors/index.js';
|
|
3
4
|
function parseNumber(value) {
|
|
4
5
|
if (value === null || value.trim().length === 0)
|
|
@@ -45,10 +46,9 @@ function buildFilter(url) {
|
|
|
45
46
|
// ---------------------------------------------------------------------------
|
|
46
47
|
/** Max ingest payload (4 MiB) — reject larger bodies with 413 */
|
|
47
48
|
const OTLP_INGEST_MAX_BODY_BYTES = 4 * 1024 * 1024;
|
|
48
|
-
/** Accepted content-types for OTLP/HTTP
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
];
|
|
49
|
+
/** Accepted content-types for OTLP/HTTP ingest. */
|
|
50
|
+
const OTLP_JSON_CONTENT_TYPE = 'application/json';
|
|
51
|
+
const OTLP_PROTOBUF_CONTENT_TYPES = new Set(['application/x-protobuf', 'application/protobuf']);
|
|
52
52
|
const OTLP_PARTIAL_SUCCESS_KEYS = {
|
|
53
53
|
logs: 'partialSuccess',
|
|
54
54
|
traces: 'partialSuccess',
|
|
@@ -58,18 +58,19 @@ const OTLP_PARTIAL_SUCCESS_KEYS = {
|
|
|
58
58
|
* Validate and parse an OTLP HTTP ingest request body.
|
|
59
59
|
* Returns a parsed JSON Record on success, or a Response (error) on failure.
|
|
60
60
|
*
|
|
61
|
-
* Protocol: OTLP/HTTP spec §4.2 —
|
|
62
|
-
*
|
|
63
|
-
* for a future release.
|
|
61
|
+
* Protocol: OTLP/HTTP spec §4.2 — supports JSON and binary protobuf service
|
|
62
|
+
* requests for logs, traces, and metrics.
|
|
64
63
|
*/
|
|
65
|
-
async function parseOtlpBody(req) {
|
|
64
|
+
async function parseOtlpBody(req, kind) {
|
|
66
65
|
const contentType = (req.headers.get('content-type') ?? '').toLowerCase().split(';')[0].trim();
|
|
67
|
-
|
|
66
|
+
const acceptsJson = contentType === OTLP_JSON_CONTENT_TYPE;
|
|
67
|
+
const acceptsProtobuf = OTLP_PROTOBUF_CONTENT_TYPES.has(contentType);
|
|
68
|
+
if (!acceptsJson && !acceptsProtobuf) {
|
|
68
69
|
return Response.json({
|
|
69
70
|
error: `Unsupported Content-Type '${contentType}' for OTLP ingest`,
|
|
70
71
|
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
71
72
|
category: DaemonErrorCategory.BAD_REQUEST,
|
|
72
|
-
hint: `Use 'application/
|
|
73
|
+
hint: `Use '${OTLP_JSON_CONTENT_TYPE}' or 'application/x-protobuf'.`,
|
|
73
74
|
}, { status: 415 });
|
|
74
75
|
}
|
|
75
76
|
const raw = await req.arrayBuffer();
|
|
@@ -80,6 +81,14 @@ async function parseOtlpBody(req) {
|
|
|
80
81
|
category: DaemonErrorCategory.BAD_REQUEST,
|
|
81
82
|
}, { status: 413 });
|
|
82
83
|
}
|
|
84
|
+
if (acceptsProtobuf) {
|
|
85
|
+
try {
|
|
86
|
+
return decodeOtlpProtobuf(kind, new Uint8Array(raw));
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return Response.json({ error: 'OTLP ingest body is not valid protobuf', code: 'INVALID_PAYLOAD', category: DaemonErrorCategory.BAD_REQUEST }, { status: 400 });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
83
92
|
try {
|
|
84
93
|
const text = new TextDecoder().decode(raw);
|
|
85
94
|
const parsed = JSON.parse(text);
|
|
@@ -289,7 +298,7 @@ export function createDaemonTelemetryRouteHandlers(context) {
|
|
|
289
298
|
if (!auth) {
|
|
290
299
|
return Response.json({ error: 'Authentication required for OTLP ingest', code: 'AUTH_REQUIRED', category: DaemonErrorCategory.AUTHENTICATION, status: 401 }, { status: 401 });
|
|
291
300
|
}
|
|
292
|
-
const bodyOrErr = await parseOtlpBody(req);
|
|
301
|
+
const bodyOrErr = await parseOtlpBody(req, 'logs');
|
|
293
302
|
if (bodyOrErr instanceof Response)
|
|
294
303
|
return bodyOrErr;
|
|
295
304
|
context.ingestSink?.ingestLogs(bodyOrErr);
|
|
@@ -300,7 +309,7 @@ export function createDaemonTelemetryRouteHandlers(context) {
|
|
|
300
309
|
if (!auth) {
|
|
301
310
|
return Response.json({ error: 'Authentication required for OTLP ingest', code: 'AUTH_REQUIRED', category: DaemonErrorCategory.AUTHENTICATION, status: 401 }, { status: 401 });
|
|
302
311
|
}
|
|
303
|
-
const bodyOrErr = await parseOtlpBody(req);
|
|
312
|
+
const bodyOrErr = await parseOtlpBody(req, 'traces');
|
|
304
313
|
if (bodyOrErr instanceof Response)
|
|
305
314
|
return bodyOrErr;
|
|
306
315
|
context.ingestSink?.ingestTraces(bodyOrErr);
|
|
@@ -311,7 +320,7 @@ export function createDaemonTelemetryRouteHandlers(context) {
|
|
|
311
320
|
if (!auth) {
|
|
312
321
|
return Response.json({ error: 'Authentication required for OTLP ingest', code: 'AUTH_REQUIRED', category: DaemonErrorCategory.AUTHENTICATION, status: 401 }, { status: 401 });
|
|
313
322
|
}
|
|
314
|
-
const bodyOrErr = await parseOtlpBody(req);
|
|
323
|
+
const bodyOrErr = await parseOtlpBody(req, 'metrics');
|
|
315
324
|
if (bodyOrErr instanceof Response)
|
|
316
325
|
return bodyOrErr;
|
|
317
326
|
context.ingestSink?.ingestMetrics(bodyOrErr);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/adapters/ntfy/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/adapters/ntfy/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAQzD,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4B9G;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,qBAAqB,EAC9B,GAAG,CAAC,EAAE,GAAG,GACR,OAAO,CAAC,QAAQ,CAAC,CAyBnB"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
1
2
|
import { parseJsonRecord, readBearerOrHeaderToken, readTextBodyWithinLimit } from '../helpers.js';
|
|
3
|
+
import { GOODVIBES_NTFY_AGENT_TOPIC, GOODVIBES_NTFY_CHAT_TOPIC, GOODVIBES_NTFY_REMOTE_TOPIC, isGoodVibesNtfyDeliveryEcho, } from '../../integrations/ntfy.js';
|
|
2
4
|
export async function handleNtfySurfaceWebhook(req, context) {
|
|
3
5
|
const enabled = Boolean(context.configManager.get('surfaces.ntfy.enabled'));
|
|
4
6
|
const configuredToken = String(context.configManager.get('surfaces.ntfy.token') ?? '')
|
|
@@ -30,6 +32,9 @@ export async function handleNtfySurfaceWebhook(req, context) {
|
|
|
30
32
|
return handleNtfySurfacePayload(body, context, new URL(req.url));
|
|
31
33
|
}
|
|
32
34
|
export async function handleNtfySurfacePayload(body, context, url) {
|
|
35
|
+
if (isGoodVibesNtfyDeliveryEcho(body)) {
|
|
36
|
+
return Response.json({ acknowledged: true, queued: false, ignored: 'goodvibes-self-echo' });
|
|
37
|
+
}
|
|
33
38
|
const topic = typeof body.topic === 'string'
|
|
34
39
|
? body.topic
|
|
35
40
|
: url?.searchParams.get('topic') ?? '';
|
|
@@ -41,6 +46,18 @@ export async function handleNtfySurfacePayload(body, context, url) {
|
|
|
41
46
|
if (!topic) {
|
|
42
47
|
return Response.json({ error: 'Missing ntfy topic' }, { status: 400 });
|
|
43
48
|
}
|
|
49
|
+
if (topic === GOODVIBES_NTFY_CHAT_TOPIC) {
|
|
50
|
+
return handleNtfyChatPayload(body, context, topic, message);
|
|
51
|
+
}
|
|
52
|
+
if (topic === GOODVIBES_NTFY_REMOTE_TOPIC) {
|
|
53
|
+
return handleNtfyRemoteChatPayload(body, context, topic, message);
|
|
54
|
+
}
|
|
55
|
+
if (topic !== GOODVIBES_NTFY_AGENT_TOPIC) {
|
|
56
|
+
return Response.json({ acknowledged: true, queued: false, ignored: 'unknown-ntfy-topic', topic });
|
|
57
|
+
}
|
|
58
|
+
return handleNtfyAgentPayload(body, context, topic, message);
|
|
59
|
+
}
|
|
60
|
+
async function authorizeNtfyPayload(body, context, topic, message) {
|
|
44
61
|
const policy = await context.authorizeSurfaceIngress({
|
|
45
62
|
surface: 'ntfy',
|
|
46
63
|
channelId: topic,
|
|
@@ -53,6 +70,81 @@ export async function handleNtfySurfacePayload(body, context, url) {
|
|
|
53
70
|
if (!policy.allowed) {
|
|
54
71
|
return Response.json({ error: `Blocked by channel policy: ${policy.reason}` }, { status: 403 });
|
|
55
72
|
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
async function handleNtfyChatPayload(body, context, topic, message) {
|
|
76
|
+
const denied = await authorizeNtfyPayload(body, context, topic, message);
|
|
77
|
+
if (denied)
|
|
78
|
+
return denied;
|
|
79
|
+
if (!message) {
|
|
80
|
+
return Response.json({ acknowledged: true, queued: false, topic });
|
|
81
|
+
}
|
|
82
|
+
if (!context.publishConversationFollowup) {
|
|
83
|
+
return Response.json({ error: 'ntfy chat routing is unavailable in this runtime' }, { status: 503 });
|
|
84
|
+
}
|
|
85
|
+
const session = await context.sessionBroker.findPreferredSession({ surfaceKind: 'tui' });
|
|
86
|
+
if (!session) {
|
|
87
|
+
return Response.json({ error: 'No active terminal TUI session is available for ntfy chat' }, { status: 409 });
|
|
88
|
+
}
|
|
89
|
+
const messageId = randomUUID();
|
|
90
|
+
const timestamp = Date.now();
|
|
91
|
+
await context.sessionBroker.appendCompanionMessage(session.id, {
|
|
92
|
+
messageId,
|
|
93
|
+
body: message,
|
|
94
|
+
source: 'ntfy-chat',
|
|
95
|
+
timestamp,
|
|
96
|
+
});
|
|
97
|
+
context.queueNtfyChatReply?.({
|
|
98
|
+
sessionId: session.id,
|
|
99
|
+
topic,
|
|
100
|
+
body: message,
|
|
101
|
+
title: typeof body.title === 'string' ? body.title : 'GoodVibes chat',
|
|
102
|
+
messageId,
|
|
103
|
+
});
|
|
104
|
+
context.publishConversationFollowup(session.id, {
|
|
105
|
+
messageId,
|
|
106
|
+
body: message,
|
|
107
|
+
source: 'ntfy-chat',
|
|
108
|
+
timestamp,
|
|
109
|
+
metadata: { surface: 'ntfy', topic },
|
|
110
|
+
});
|
|
111
|
+
return Response.json({
|
|
112
|
+
acknowledged: true,
|
|
113
|
+
queued: false,
|
|
114
|
+
routedTo: 'tui-chat',
|
|
115
|
+
sessionId: session.id,
|
|
116
|
+
messageId,
|
|
117
|
+
topic,
|
|
118
|
+
}, { status: 202 });
|
|
119
|
+
}
|
|
120
|
+
async function handleNtfyRemoteChatPayload(body, context, topic, message) {
|
|
121
|
+
const denied = await authorizeNtfyPayload(body, context, topic, message);
|
|
122
|
+
if (denied)
|
|
123
|
+
return denied;
|
|
124
|
+
if (!message) {
|
|
125
|
+
return Response.json({ acknowledged: true, queued: false, topic });
|
|
126
|
+
}
|
|
127
|
+
if (!context.postNtfyRemoteChatMessage) {
|
|
128
|
+
return Response.json({ error: 'ntfy remote chat is unavailable in this runtime' }, { status: 503 });
|
|
129
|
+
}
|
|
130
|
+
const result = await context.postNtfyRemoteChatMessage({
|
|
131
|
+
topic,
|
|
132
|
+
body: message,
|
|
133
|
+
title: typeof body.title === 'string' ? body.title : 'GoodVibes ntfy',
|
|
134
|
+
});
|
|
135
|
+
return Response.json({
|
|
136
|
+
acknowledged: true,
|
|
137
|
+
queued: false,
|
|
138
|
+
routedTo: 'ntfy-remote-chat',
|
|
139
|
+
...result,
|
|
140
|
+
topic,
|
|
141
|
+
}, { status: result.error ? 502 : 202 });
|
|
142
|
+
}
|
|
143
|
+
async function handleNtfyAgentPayload(body, context, topic, message) {
|
|
144
|
+
const denied = await authorizeNtfyPayload(body, context, topic, message);
|
|
145
|
+
if (denied)
|
|
146
|
+
return denied;
|
|
147
|
+
const preferredTuiSession = await context.sessionBroker.findPreferredSession({ surfaceKind: 'tui' });
|
|
56
148
|
const binding = await context.routeBindings.upsertBinding({
|
|
57
149
|
kind: 'channel',
|
|
58
150
|
surfaceKind: 'ntfy',
|
|
@@ -66,6 +158,7 @@ export async function handleNtfySurfacePayload(body, context, url) {
|
|
|
66
158
|
return Response.json({ acknowledged: true, queued: false, bindingId: binding.id });
|
|
67
159
|
}
|
|
68
160
|
const submission = await context.sessionBroker.submitMessage({
|
|
161
|
+
...(preferredTuiSession ? { sessionId: preferredTuiSession.id } : {}),
|
|
69
162
|
routeId: binding.id,
|
|
70
163
|
surfaceKind: 'ntfy',
|
|
71
164
|
surfaceId: binding.surfaceId,
|
|
@@ -4,6 +4,7 @@ import type { AutomationRouteBinding } from '../automation/routes.js';
|
|
|
4
4
|
import type { AutomationSurfaceKind } from '../automation/types.js';
|
|
5
5
|
import type { ChannelConversationKind, ChannelPolicyDecision, RouteBindingManager } from '../channels/index.js';
|
|
6
6
|
import type { SharedSessionBroker } from '../control-plane/index.js';
|
|
7
|
+
import type { ConversationMessageEnvelope } from '../control-plane/conversation-message.js';
|
|
7
8
|
import type { ServiceRegistry } from '../config/service-registry.js';
|
|
8
9
|
export interface SurfaceControlCommand {
|
|
9
10
|
readonly action: 'status' | 'cancel' | 'retry';
|
|
@@ -14,6 +15,19 @@ export interface QueueSurfaceReplyInput {
|
|
|
14
15
|
readonly task: string;
|
|
15
16
|
readonly sessionId?: string;
|
|
16
17
|
}
|
|
18
|
+
export interface QueueNtfyChatReplyInput {
|
|
19
|
+
readonly sessionId: string;
|
|
20
|
+
readonly topic: string;
|
|
21
|
+
readonly body: string;
|
|
22
|
+
readonly title?: string;
|
|
23
|
+
readonly messageId: string;
|
|
24
|
+
}
|
|
25
|
+
export interface NtfyRemoteChatResult {
|
|
26
|
+
readonly sessionId: string;
|
|
27
|
+
readonly messageId: string;
|
|
28
|
+
readonly delivered: boolean;
|
|
29
|
+
readonly error?: string;
|
|
30
|
+
}
|
|
17
31
|
export type TrySpawnAgentInput = Parameters<AgentManager['spawn']>[0];
|
|
18
32
|
export type TrySpawnAgentResult = AgentRecord | Response;
|
|
19
33
|
export type TrySpawnAgentFn = (input: TrySpawnAgentInput, logLabel: string, sessionId?: string) => TrySpawnAgentResult;
|
|
@@ -43,6 +57,13 @@ export interface SurfaceAdapterContext {
|
|
|
43
57
|
readonly performInteractiveSurfaceAction: (actionId: string, surface: 'slack' | 'discord', req: Request) => Promise<string>;
|
|
44
58
|
readonly trySpawnAgent: TrySpawnAgentFn;
|
|
45
59
|
readonly queueSurfaceReplyFromBinding: (binding: AutomationRouteBinding | undefined, input: QueueSurfaceReplyInput) => void;
|
|
60
|
+
readonly publishConversationFollowup?: (sessionId: string, envelope: Omit<ConversationMessageEnvelope, 'sessionId'>) => void;
|
|
61
|
+
readonly queueNtfyChatReply?: (input: QueueNtfyChatReplyInput) => void;
|
|
62
|
+
readonly postNtfyRemoteChatMessage?: (input: {
|
|
63
|
+
readonly topic: string;
|
|
64
|
+
readonly body: string;
|
|
65
|
+
readonly title?: string;
|
|
66
|
+
}) => Promise<NtfyRemoteChatResult>;
|
|
46
67
|
}
|
|
47
68
|
export interface GenericWebhookReplyInput {
|
|
48
69
|
readonly agentId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/adapters/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/adapters/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/channels/builtin/setup-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAClB,cAAc,EACf,MAAM,aAAa,CAAC;AAMrB,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"setup-schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/channels/builtin/setup-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,kBAAkB,EAClB,cAAc,EACf,MAAM,aAAa,CAAC;AAMrB,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,kBAAkB,CAwcjF"}
|
|
@@ -116,11 +116,11 @@ export function getBuiltinSetupSchema(surface) {
|
|
|
116
116
|
version: CHANNEL_SETUP_VERSION,
|
|
117
117
|
label: 'ntfy',
|
|
118
118
|
setupMode: 'webhook',
|
|
119
|
-
description: 'ntfy is a notification surface backed by
|
|
119
|
+
description: 'ntfy is a notification and remote-control surface backed by SDK-owned inbound topics, optional delivery topics, and optional authentication.',
|
|
120
120
|
fields: [
|
|
121
121
|
setupField('enabled', 'Enabled', 'boolean', false, { configKey: 'surfaces.ntfy.enabled', defaultValue: false }),
|
|
122
122
|
setupField('baseUrl', 'Base URL', 'url', false, { configKey: 'surfaces.ntfy.baseUrl', placeholder: 'https://ntfy.sh' }),
|
|
123
|
-
setupField('topic', '
|
|
123
|
+
setupField('topic', 'Default delivery topic', 'string', false, { configKey: 'surfaces.ntfy.topic' }),
|
|
124
124
|
setupField('token', 'Access token', 'secret', false, { configKey: 'surfaces.ntfy.token', secretTargetId: 'primary' }),
|
|
125
125
|
],
|
|
126
126
|
secretTargets: [
|
|
@@ -132,7 +132,8 @@ export function getBuiltinSetupSchema(surface) {
|
|
|
132
132
|
}),
|
|
133
133
|
],
|
|
134
134
|
externalSteps: [
|
|
135
|
-
'
|
|
135
|
+
'Subscribe the daemon to the SDK-owned goodvibes-chat, goodvibes-agent, and goodvibes-ntfy topics.',
|
|
136
|
+
'Optionally configure a default delivery topic for outbound notifications.',
|
|
136
137
|
'Optionally configure an authenticated ntfy token.',
|
|
137
138
|
'Use provider actions to inspect subscribe and poll URLs.',
|
|
138
139
|
],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strategies-core.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/channels/delivery/strategies-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAc1D,wBAAgB,6BAA6B,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,GAAG,uBAAuB,CAsCjI;AAED,wBAAgB,2BAA2B,CACzC,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA0CzB;AAED,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA2CzB;AAED,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,
|
|
1
|
+
{"version":3,"file":"strategies-core.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/channels/delivery/strategies-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAGrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAc1D,wBAAgB,6BAA6B,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,GAAG,uBAAuB,CAsCjI;AAED,wBAAgB,2BAA2B,CACzC,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA0CzB;AAED,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA2CzB;AAED,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CAwBzB;AAED,wBAAgB,qCAAqC,CACnD,aAAa,EAAE,aAAa,EAC5B,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,MAAM,mBAAmB,GAAG,IAAI,GAC3C,uBAAuB,CA6BzB;AAED,wBAAgB,8BAA8B,CAC5C,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CAqCzB;AAED,wBAAgB,gCAAgC,CAC9C,aAAa,EAAE,aAAa,EAC5B,eAAe,EAAE,eAAe,EAChC,aAAa,EAAE,aAAa,GAC3B,uBAAuB,CA+BzB"}
|
|
@@ -145,6 +145,7 @@ export function createNtfyDeliveryStrategy(configManager, serviceRegistry, artif
|
|
|
145
145
|
title: request.target.label ?? titleFromBody(request.body),
|
|
146
146
|
...(request.includeLinks && baseUrlHint ? { click: `${baseUrlHint.replace(/\/+$/, '')}/api/control-plane/web` } : {}),
|
|
147
147
|
...(primaryAttachment?.contentUrl ? { attach: primaryAttachment.contentUrl } : {}),
|
|
148
|
+
markGoodVibesOrigin: true,
|
|
148
149
|
});
|
|
149
150
|
return success(topic);
|
|
150
151
|
},
|
|
@@ -45,7 +45,7 @@ export declare class ChannelProviderRuntimeManager {
|
|
|
45
45
|
private resolveSlackAppToken;
|
|
46
46
|
private resolveDiscordBotToken;
|
|
47
47
|
private resolveNtfyToken;
|
|
48
|
-
private
|
|
48
|
+
private resolveNtfyTopics;
|
|
49
49
|
private isConfigured;
|
|
50
50
|
private markStarted;
|
|
51
51
|
private markStopped;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-runtime.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/channels/provider-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"provider-runtime.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/channels/provider-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAYrE,OAAO,EACL,KAAK,qBAAqB,EAI3B,MAAM,sBAAsB,CAAC;AAI9B,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,UAAU,0BAA0B;IAClC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;CAClE;AAeD,qBAAa,6BAA6B;IAU5B,OAAO,CAAC,QAAQ,CAAC,IAAI;IATjC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAIpB;gBAE2B,IAAI,EAAE,0BAA0B;IAEvD,eAAe,IAAI,OAAO,CAAC,2BAA2B,EAAE,CAAC;IAczD,KAAK,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAMlF,IAAI,CAAC,OAAO,EAAE,sBAAsB,GAAG,2BAA2B;IAmBlE,OAAO,IAAI,IAAI;IAMf,MAAM,CAAC,OAAO,EAAE,sBAAsB,GAAG,qBAAqB;YAchD,UAAU;YAoCV,YAAY;YA8BZ,SAAS;YA8BT,mBAAmB;YASnB,qBAAqB;YASrB,iBAAiB;YASjB,oBAAoB;YAQpB,oBAAoB;YAMpB,sBAAsB;YAQtB,gBAAgB;IAQ9B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,MAAM;CAQf"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DiscordGatewayClient, DiscordIntegration, NtfyIntegration, SlackIntegration, SlackSocketModeClient, } from '../integrations/index.js';
|
|
1
|
+
import { DiscordGatewayClient, DiscordIntegration, GOODVIBES_NTFY_DEFAULT_TOPICS, NtfyIntegration, SlackIntegration, SlackSocketModeClient, } from '../integrations/index.js';
|
|
2
2
|
import { handleDiscordGatewayDispatchPayload, handleNtfySurfacePayload, handleSlackSurfacePayload, } from '../adapters/index.js';
|
|
3
3
|
import { logger } from '../utils/logger.js';
|
|
4
4
|
import { summarizeError } from '../utils/error-display.js';
|
|
@@ -27,7 +27,7 @@ export class ChannelProviderRuntimeManager {
|
|
|
27
27
|
if (this.deps.configManager.get('surfaces.discord.enabled') && await this.resolveDiscordBotToken()) {
|
|
28
28
|
results.push(await this.start('discord'));
|
|
29
29
|
}
|
|
30
|
-
if (this.deps.configManager.get('surfaces.ntfy.enabled') && this.
|
|
30
|
+
if (this.deps.configManager.get('surfaces.ntfy.enabled') && this.resolveNtfyTopics().length > 0) {
|
|
31
31
|
results.push(await this.start('ntfy'));
|
|
32
32
|
}
|
|
33
33
|
return results;
|
|
@@ -139,16 +139,17 @@ export class ChannelProviderRuntimeManager {
|
|
|
139
139
|
if (this.ntfyAbort) {
|
|
140
140
|
return this.result('ntfy', true, 'ntfy JSON stream runtime is already running.');
|
|
141
141
|
}
|
|
142
|
-
const
|
|
143
|
-
if (
|
|
142
|
+
const topics = this.resolveNtfyTopics();
|
|
143
|
+
if (topics.length === 0) {
|
|
144
144
|
this.markError('ntfy', 'ntfy topic is required for subscription runtime.');
|
|
145
145
|
return this.result('ntfy', false, 'ntfy topic is required for subscription runtime.');
|
|
146
146
|
}
|
|
147
147
|
const abort = new AbortController();
|
|
148
148
|
this.ntfyAbort = abort;
|
|
149
149
|
const ntfy = new NtfyIntegration(String(this.deps.configManager.get('surfaces.ntfy.baseUrl') || 'https://ntfy.sh'), await this.resolveNtfyToken() ?? undefined);
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
const topicList = topics.join(',');
|
|
151
|
+
this.markStarted('ntfy', { topics });
|
|
152
|
+
void ntfy.subscribeJsonStream(topicList, (message) => this.handleNtfyMessage(message), {
|
|
152
153
|
since: 'latest',
|
|
153
154
|
signal: abort.signal,
|
|
154
155
|
}).catch((error) => {
|
|
@@ -213,8 +214,12 @@ export class ChannelProviderRuntimeManager {
|
|
|
213
214
|
|| process.env.NTFY_ACCESS_TOKEN
|
|
214
215
|
|| null;
|
|
215
216
|
}
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
resolveNtfyTopics() {
|
|
218
|
+
const configured = String(this.deps.configManager.get('surfaces.ntfy.topic') || '')
|
|
219
|
+
.split(',')
|
|
220
|
+
.map((topic) => topic.trim())
|
|
221
|
+
.filter((topic) => topic.length > 0);
|
|
222
|
+
return [...new Set([...GOODVIBES_NTFY_DEFAULT_TOPICS, ...configured])];
|
|
218
223
|
}
|
|
219
224
|
isConfigured(surface) {
|
|
220
225
|
if (surface === 'slack') {
|
|
@@ -223,7 +228,7 @@ export class ChannelProviderRuntimeManager {
|
|
|
223
228
|
if (surface === 'discord') {
|
|
224
229
|
return Boolean(this.deps.configManager.get('surfaces.discord.botToken') || process.env.DISCORD_BOT_TOKEN);
|
|
225
230
|
}
|
|
226
|
-
return
|
|
231
|
+
return this.resolveNtfyTopics().length > 0;
|
|
227
232
|
}
|
|
228
233
|
markStarted(surface, metadata) {
|
|
229
234
|
this.state[surface] = {
|
|
@@ -34,6 +34,7 @@ export declare class ChannelReplyPipeline {
|
|
|
34
34
|
deliverProgress(agentId: string, explicitText?: string, force?: boolean): Promise<ChannelRenderResult | null>;
|
|
35
35
|
deliverFinal(agentId: string, explicitText: string): Promise<ChannelRenderResult | null>;
|
|
36
36
|
private handleEnvelope;
|
|
37
|
+
private trackChildPendingReply;
|
|
37
38
|
private resolvePolicy;
|
|
38
39
|
private dispatch;
|
|
39
40
|
private disposeSubscriptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reply-pipeline.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/channels/reply-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACzG,OAAO,KAAK,EACV,kBAAkB,EAIlB,mBAAmB,EAEnB,cAAc,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC;IAC/C,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;
|
|
1
|
+
{"version":3,"file":"reply-pipeline.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/channels/reply-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AACzG,OAAO,KAAK,EACV,kBAAkB,EAIlB,mBAAmB,EAEnB,cAAc,EACf,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACjC;AAED,UAAU,iBAAiB;IACzB,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC;IAC/C,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AA+OD,wBAAgB,sCAAsC,CACpD,QAAQ,EAAE,oBAAoB,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC,GACvE,kBAAkB,EAAE,CAyFtB;AAED,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;gBAE3C,IAAI,EAAE,iBAAiB;IAOnC,gBAAgB,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI;IAmB1D,OAAO,IAAI,IAAI;IAKf,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAOhD,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI9B,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI7B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI;IAIjD,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAe3G,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;YAwBhF,cAAc;IAsC5B,OAAO,CAAC,sBAAsB;YAmBhB,aAAa;YAIb,QAAQ;IAgCtB,OAAO,CAAC,oBAAoB;CAK7B"}
|
|
@@ -211,6 +211,12 @@ function renderEvent(kind, phase, envelope, extras = {}) {
|
|
|
211
211
|
...extras,
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
|
+
function resolveEnvelopeAgentId(envelope) {
|
|
215
|
+
if (envelope.agentId)
|
|
216
|
+
return envelope.agentId;
|
|
217
|
+
const payload = envelope.payload;
|
|
218
|
+
return typeof payload.agentId === 'string' ? payload.agentId : null;
|
|
219
|
+
}
|
|
214
220
|
export function normalizeChannelRenderEventFromRuntime(envelope) {
|
|
215
221
|
const payload = envelope.payload;
|
|
216
222
|
switch (payload.type) {
|
|
@@ -386,7 +392,12 @@ export class ChannelReplyPipeline {
|
|
|
386
392
|
return result;
|
|
387
393
|
}
|
|
388
394
|
async handleEnvelope(envelope) {
|
|
389
|
-
|
|
395
|
+
if (envelope.payload.type === 'AGENT_SPAWNING'
|
|
396
|
+
&& typeof envelope.payload.parentAgentId === 'string'
|
|
397
|
+
&& envelope.payload.parentAgentId.length > 0) {
|
|
398
|
+
this.trackChildPendingReply(envelope.payload.agentId, envelope.payload.parentAgentId, envelope.payload.task);
|
|
399
|
+
}
|
|
400
|
+
const agentId = resolveEnvelopeAgentId(envelope);
|
|
390
401
|
if (!agentId)
|
|
391
402
|
return;
|
|
392
403
|
const state = this.buffers.get(agentId);
|
|
@@ -412,6 +423,26 @@ export class ChannelReplyPipeline {
|
|
|
412
423
|
}
|
|
413
424
|
await this.deliverProgress(agentId);
|
|
414
425
|
}
|
|
426
|
+
trackChildPendingReply(agentId, parentAgentId, task) {
|
|
427
|
+
if (this.buffers.has(agentId))
|
|
428
|
+
return;
|
|
429
|
+
const parentState = this.buffers.get(parentAgentId);
|
|
430
|
+
if (!parentState)
|
|
431
|
+
return;
|
|
432
|
+
const rootAgentId = typeof parentState.pending.rootAgentId === 'string'
|
|
433
|
+
? parentState.pending.rootAgentId
|
|
434
|
+
: parentAgentId;
|
|
435
|
+
this.buffers.set(agentId, {
|
|
436
|
+
pending: {
|
|
437
|
+
...parentState.pending,
|
|
438
|
+
agentId,
|
|
439
|
+
task,
|
|
440
|
+
parentAgentId,
|
|
441
|
+
rootAgentId,
|
|
442
|
+
},
|
|
443
|
+
events: [],
|
|
444
|
+
});
|
|
445
|
+
}
|
|
415
446
|
async resolvePolicy(surface) {
|
|
416
447
|
return await this.channelPlugins.getRenderPolicy(surface) ?? DEFAULT_POLICY[surface];
|
|
417
448
|
}
|
|
@@ -50,6 +50,12 @@ export interface CompanionChatEventPublisher {
|
|
|
50
50
|
clientId?: string;
|
|
51
51
|
}): void;
|
|
52
52
|
}
|
|
53
|
+
export interface CompanionChatReplyResult {
|
|
54
|
+
readonly messageId: string;
|
|
55
|
+
readonly assistantMessageId?: string;
|
|
56
|
+
readonly response?: string;
|
|
57
|
+
readonly error?: string;
|
|
58
|
+
}
|
|
53
59
|
export interface CompanionChatManagerConfig {
|
|
54
60
|
readonly provider: CompanionLLMProvider;
|
|
55
61
|
readonly eventPublisher: CompanionChatEventPublisher;
|
|
@@ -90,6 +96,7 @@ export declare class CompanionChatManager {
|
|
|
90
96
|
private gcTimer;
|
|
91
97
|
/** Tracks whether the async init() has completed. */
|
|
92
98
|
private initCompleted;
|
|
99
|
+
private readonly pendingReplies;
|
|
93
100
|
/**
|
|
94
101
|
* Serializes persistence writes per session to prevent write-after-write
|
|
95
102
|
* races where two concurrent saves could result in an older snapshot
|
|
@@ -131,6 +138,10 @@ export declare class CompanionChatManager {
|
|
|
131
138
|
* Pass '' to skip client-level rate limiting.
|
|
132
139
|
*/
|
|
133
140
|
postMessage(sessionId: string, content: string, clientId?: string): Promise<string>;
|
|
141
|
+
postMessageAndWaitForReply(sessionId: string, content: string, clientId?: string, options?: {
|
|
142
|
+
readonly timeoutMs?: number;
|
|
143
|
+
}): Promise<CompanionChatReplyResult>;
|
|
144
|
+
private _postMessageInternal;
|
|
134
145
|
dispose(): void;
|
|
135
146
|
private _runTurn;
|
|
136
147
|
_gcSweep(): void;
|
|
@@ -143,5 +154,6 @@ export declare class CompanionChatManager {
|
|
|
143
154
|
*/
|
|
144
155
|
private _persist;
|
|
145
156
|
private _doSave;
|
|
157
|
+
private resolvePendingReply;
|
|
146
158
|
}
|
|
147
159
|
//# sourceMappingURL=companion-chat-manager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"companion-chat-manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/companion/companion-chat-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EACV,oBAAoB,EACpB,oBAAoB,EAGpB,+BAA+B,EAChC,MAAM,2BAA2B,CAAC;AAMnC,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMzD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,UAAU,CACR,QAAQ,EAAE,wBAAwB,EAAE,EACpC,OAAO,EAAE;QACP,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;KACpC,GACA,aAAa,CAAC,sBAAsB,CAAC,CAAC;CAC1C;AAMD,MAAM,WAAW,2BAA2B;IAC1C,YAAY,CACV,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7B,IAAI,CAAC;CACT;
|
|
1
|
+
{"version":3,"file":"companion-chat-manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/companion/companion-chat-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,7 @@ export class CompanionChatManager {
|
|
|
41
41
|
gcTimer = null;
|
|
42
42
|
/** Tracks whether the async init() has completed. */
|
|
43
43
|
initCompleted = false;
|
|
44
|
+
pendingReplies = new Map();
|
|
44
45
|
/**
|
|
45
46
|
* Serializes persistence writes per session to prevent write-after-write
|
|
46
47
|
* races where two concurrent saves could result in an older snapshot
|
|
@@ -195,6 +196,30 @@ export class CompanionChatManager {
|
|
|
195
196
|
* Pass '' to skip client-level rate limiting.
|
|
196
197
|
*/
|
|
197
198
|
async postMessage(sessionId, content, clientId = '') {
|
|
199
|
+
return await this._postMessageInternal(sessionId, content, clientId);
|
|
200
|
+
}
|
|
201
|
+
async postMessageAndWaitForReply(sessionId, content, clientId = '', options = {}) {
|
|
202
|
+
let messageId = '';
|
|
203
|
+
const result = new Promise((resolve) => {
|
|
204
|
+
const timeout = setTimeout(() => {
|
|
205
|
+
if (messageId)
|
|
206
|
+
this.pendingReplies.delete(messageId);
|
|
207
|
+
resolve({ messageId, error: 'Timed out waiting for companion chat reply' });
|
|
208
|
+
}, options.timeoutMs ?? 120_000);
|
|
209
|
+
timeout.unref?.();
|
|
210
|
+
void this._postMessageInternal(sessionId, content, clientId, { resolve, timeout })
|
|
211
|
+
.then((id) => { messageId = id; })
|
|
212
|
+
.catch((error) => {
|
|
213
|
+
clearTimeout(timeout);
|
|
214
|
+
resolve({
|
|
215
|
+
messageId,
|
|
216
|
+
error: error instanceof Error ? error.message : String(error),
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
async _postMessageInternal(sessionId, content, clientId, pendingReply) {
|
|
198
223
|
const session = this.sessions.get(sessionId);
|
|
199
224
|
if (!session) {
|
|
200
225
|
throw Object.assign(new Error(`Session not found: ${sessionId}`), { code: 'SESSION_NOT_FOUND', status: 404 });
|
|
@@ -222,6 +247,9 @@ export class CompanionChatManager {
|
|
|
222
247
|
});
|
|
223
248
|
// Persist async (non-blocking)
|
|
224
249
|
void this._persist(sessionId);
|
|
250
|
+
if (pendingReply) {
|
|
251
|
+
this.pendingReplies.set(messageId, pendingReply);
|
|
252
|
+
}
|
|
225
253
|
// Fire-and-forget: run the turn without blocking the HTTP response
|
|
226
254
|
void this._runTurn(session, messageId);
|
|
227
255
|
return messageId;
|
|
@@ -367,11 +395,16 @@ export class CompanionChatManager {
|
|
|
367
395
|
timestamp: now,
|
|
368
396
|
};
|
|
369
397
|
publish({ type: 'turn.completed', sessionId, turnId, assistantMessageId, envelope: completedEnvelope });
|
|
398
|
+
this.resolvePendingReply(userMessageId, { messageId: userMessageId, assistantMessageId, response: assistantContent });
|
|
370
399
|
}
|
|
371
400
|
catch (err) {
|
|
372
401
|
if (!abortSignal.aborted) {
|
|
373
402
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
374
403
|
publish({ type: 'turn.error', sessionId, turnId, error: errorMessage });
|
|
404
|
+
this.resolvePendingReply(userMessageId, { messageId: userMessageId, error: errorMessage });
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
this.resolvePendingReply(userMessageId, { messageId: userMessageId, error: 'Turn cancelled' });
|
|
375
408
|
}
|
|
376
409
|
}
|
|
377
410
|
}
|
|
@@ -434,4 +467,12 @@ export class CompanionChatManager {
|
|
|
434
467
|
return;
|
|
435
468
|
await this.persistence.save({ meta: session.meta, messages: session.messages });
|
|
436
469
|
}
|
|
470
|
+
resolvePendingReply(messageId, result) {
|
|
471
|
+
const pending = this.pendingReplies.get(messageId);
|
|
472
|
+
if (!pending)
|
|
473
|
+
return;
|
|
474
|
+
this.pendingReplies.delete(messageId);
|
|
475
|
+
clearTimeout(pending.timeout);
|
|
476
|
+
pending.resolve(result);
|
|
477
|
+
}
|
|
437
478
|
}
|