stageflow 0.36.0 → 0.39.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 +18 -8
- package/dist/agent/claudeAdapter.js +6 -0
- package/dist/agent/piAdapter.d.ts +9 -1
- package/dist/agent/piAdapter.js +21 -2
- package/dist/agent/piIsolatedMcp.js +14 -2
- package/dist/agent/piIsolatedMcpProbe.d.ts +5 -1
- package/dist/agent/piIsolatedMcpProbe.js +16 -30
- package/dist/agent/port.d.ts +5 -0
- package/dist/agents/agentId.d.ts +8 -0
- package/dist/agents/agentId.js +27 -0
- package/dist/agents/approvalBroker.d.ts +16 -0
- package/dist/agents/approvalBroker.js +45 -0
- package/dist/agents/authorChat.d.ts +19 -0
- package/dist/agents/authorChat.js +63 -0
- package/dist/agents/chatTurn.d.ts +23 -0
- package/dist/agents/chatTurn.js +77 -0
- package/dist/agents/communications/agentmail.d.ts +19 -0
- package/dist/agents/communications/agentmail.js +46 -0
- package/dist/agents/communications/agentmailListener.d.ts +59 -0
- package/dist/agents/communications/agentmailListener.js +183 -0
- package/dist/agents/communications/allowlist.d.ts +10 -0
- package/dist/agents/communications/allowlist.js +36 -0
- package/dist/agents/communications/channelConnections.d.ts +3 -0
- package/dist/agents/communications/channelConnections.js +51 -0
- package/dist/agents/communications/delivery.d.ts +53 -0
- package/dist/agents/communications/delivery.js +142 -0
- package/dist/agents/communications/email.d.ts +26 -0
- package/dist/agents/communications/email.js +20 -0
- package/dist/agents/communications/identity.d.ts +13 -0
- package/dist/agents/communications/identity.js +18 -0
- package/dist/agents/communications/imessageListener.d.ts +41 -0
- package/dist/agents/communications/imessageListener.js +92 -0
- package/dist/agents/communications/inbound.d.ts +63 -0
- package/dist/agents/communications/inbound.js +143 -0
- package/dist/agents/communications/listener.d.ts +36 -0
- package/dist/agents/communications/listener.js +38 -0
- package/dist/agents/communications/photon.d.ts +19 -0
- package/dist/agents/communications/photon.js +38 -0
- package/dist/agents/communications/port.d.ts +27 -0
- package/dist/agents/communications/port.js +6 -0
- package/dist/agents/communications/slack.d.ts +28 -0
- package/dist/agents/communications/slack.js +65 -0
- package/dist/agents/communications/supervisor.d.ts +36 -0
- package/dist/agents/communications/supervisor.js +96 -0
- package/dist/agents/communications/telegram.d.ts +19 -0
- package/dist/agents/communications/telegram.js +52 -0
- package/dist/agents/definitionSummary.d.ts +13 -0
- package/dist/agents/definitionSummary.js +91 -0
- package/dist/agents/delegate.d.ts +3 -0
- package/dist/agents/delegate.js +8 -0
- package/dist/agents/errors.d.ts +10 -0
- package/dist/agents/errors.js +32 -0
- package/dist/agents/guardrails.d.ts +24 -0
- package/dist/agents/guardrails.js +39 -0
- package/dist/agents/historyFit.d.ts +10 -0
- package/dist/agents/historyFit.js +26 -0
- package/dist/agents/hostContext.d.ts +54 -0
- package/dist/agents/hostContext.js +156 -0
- package/dist/agents/ledgers.d.ts +29 -0
- package/dist/agents/ledgers.js +31 -0
- package/dist/agents/lineDiff.d.ts +12 -0
- package/dist/agents/lineDiff.js +46 -0
- package/dist/agents/ndjson.d.ts +9 -0
- package/dist/agents/ndjson.js +47 -0
- package/dist/agents/otlpExport.d.ts +9 -0
- package/dist/agents/otlpExport.js +58 -0
- package/dist/agents/otlpSink.d.ts +7 -0
- package/dist/agents/otlpSink.js +23 -0
- package/dist/agents/policy.d.ts +31 -0
- package/dist/agents/policy.js +84 -0
- package/dist/agents/projectRoot.d.ts +5 -0
- package/dist/agents/projectRoot.js +15 -0
- package/dist/agents/runtime/piRuntime.d.ts +52 -0
- package/dist/agents/runtime/piRuntime.js +474 -0
- package/dist/agents/runtime/types.d.ts +77 -0
- package/dist/agents/runtime/types.js +26 -0
- package/dist/agents/sandbox.d.ts +17 -0
- package/dist/agents/sandbox.js +10 -0
- package/dist/agents/scheduleSource.d.ts +32 -0
- package/dist/agents/scheduleSource.js +100 -0
- package/dist/agents/service.d.ts +298 -0
- package/dist/agents/service.js +1105 -0
- package/dist/agents/sessions.d.ts +38 -0
- package/dist/agents/sessions.js +321 -0
- package/dist/agents/store.d.ts +277 -0
- package/dist/agents/store.js +643 -0
- package/dist/agents/trace.d.ts +27 -0
- package/dist/agents/trace.js +29 -0
- package/dist/agents/turnLifecycle.d.ts +72 -0
- package/dist/agents/turnLifecycle.js +157 -0
- package/dist/agents/webChat/publicChat.d.ts +36 -0
- package/dist/agents/webChat/publicChat.js +290 -0
- package/dist/agents/webChat/rateLimit.d.ts +15 -0
- package/dist/agents/webChat/rateLimit.js +33 -0
- package/dist/agents/webChat/slug.d.ts +2 -0
- package/dist/agents/webChat/slug.js +9 -0
- package/dist/channels/providers/agentmail.js +14 -1
- package/dist/channels/providers/photonImessage.js +36 -0
- package/dist/channels/providers/slack.js +2 -1
- package/dist/channels/providers/telegram.js +2 -1
- package/dist/channels/types.d.ts +27 -0
- package/dist/cli/agentsCommand.d.ts +14 -0
- package/dist/cli/agentsCommand.js +291 -0
- package/dist/cli.js +9 -0
- package/dist/config/browseCatalog.js +4 -11
- package/dist/config/draftPackage.d.ts +1 -0
- package/dist/config/draftPackage.js +4 -0
- package/dist/config/hostConfig.js +7 -0
- package/dist/config/loadAgent.d.ts +266 -0
- package/dist/config/loadAgent.js +374 -0
- package/dist/config/loadPipeline.js +5 -2
- package/dist/config/mcpHostCatalog.d.ts +50 -0
- package/dist/config/mcpHostCatalog.js +405 -0
- package/dist/config/mcpOAuth.d.ts +37 -0
- package/dist/config/mcpOAuth.js +263 -0
- package/dist/config/mcpRedaction.d.ts +42 -0
- package/dist/config/mcpRedaction.js +314 -0
- package/dist/config/mcpToolCache.d.ts +20 -0
- package/dist/config/mcpToolCache.js +43 -0
- package/dist/config/mergePipelineIncludes.d.ts +2 -0
- package/dist/config/mergePipelineIncludes.js +25 -0
- package/dist/config/resolveStageMcpServers.d.ts +35 -3
- package/dist/config/resolveStageMcpServers.js +124 -9
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +22 -1
- package/dist/mcp/agentTools.d.ts +8 -0
- package/dist/mcp/agentTools.js +132 -0
- package/dist/mcp/catalogTools.js +6 -9
- package/dist/mcp/deps.d.ts +6 -0
- package/dist/mcp/pipelineAuthorSupport.d.ts +19 -0
- package/dist/mcp/pipelineAuthorSupport.js +10 -0
- package/dist/mcp/pipelineAuthorTools.d.ts +8 -0
- package/dist/mcp/pipelineAuthorTools.js +109 -0
- package/dist/mcp/server.js +5 -0
- package/dist/mcp/tools.js +4 -0
- package/dist/mcp/triggerTools.js +32 -0
- package/dist/memory/access.d.ts +36 -0
- package/dist/memory/access.js +116 -0
- package/dist/memory/agentIssues.d.ts +3 -0
- package/dist/memory/agentIssues.js +23 -0
- package/dist/memory/bashDeny.d.ts +6 -0
- package/dist/memory/bashDeny.js +35 -0
- package/dist/memory/host.d.ts +51 -0
- package/dist/memory/host.js +394 -0
- package/dist/memory/ids.d.ts +15 -0
- package/dist/memory/ids.js +31 -0
- package/dist/memory/worker.d.ts +1 -0
- package/dist/memory/worker.js +84 -0
- package/dist/models/catalog.d.ts +113 -0
- package/dist/models/catalog.js +238 -0
- package/dist/models/response.d.ts +29 -0
- package/dist/models/response.js +25 -0
- package/dist/operatorAgent/agentAuthorContext.d.ts +17 -0
- package/dist/operatorAgent/agentAuthorContext.js +32 -0
- package/dist/operatorAgent/fakeHost.js +2 -0
- package/dist/operatorAgent/host.js +6 -3
- package/dist/operatorAgent/index.d.ts +4 -0
- package/dist/operatorAgent/index.js +4 -0
- package/dist/operatorAgent/piModel.js +2 -0
- package/dist/operatorAgent/profiles/agentAuthor.d.ts +11 -0
- package/dist/operatorAgent/profiles/agentAuthor.js +192 -0
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -0
- package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +29 -0
- package/dist/operatorAgent/profiles/workshopAuthor.js +2 -2
- package/dist/operatorAgent/profiles/workshopAuthorTools.js +3 -3
- package/dist/operatorAgent/proposals.d.ts +1 -0
- package/dist/operatorAgent/proposals.js +23 -2
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/preflight/pipelinePreflight.js +1 -0
- package/dist/runstore/createStore.d.ts +2 -0
- package/dist/runstore/createStore.js +8 -0
- package/dist/runstore/overviewSummary.d.ts +56 -0
- package/dist/runstore/overviewSummary.js +134 -0
- package/dist/runstore/port.d.ts +3 -0
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +2 -0
- package/dist/runstore/sqlite/SqliteRunStore.js +18 -0
- package/dist/runstore/sqlite/migrations/013-agents.d.ts +12 -0
- package/dist/runstore/sqlite/migrations/013-agents.js +156 -0
- package/dist/runstore/sqlite/migrations/014-agent-deliveries.d.ts +11 -0
- package/dist/runstore/sqlite/migrations/014-agent-deliveries.js +32 -0
- package/dist/runstore/sqlite/migrations/index.js +4 -0
- package/dist/runtime/stageAttemptBootstrap.js +15 -1
- package/dist/runtime/stageEnvironment.d.ts +2 -0
- package/dist/runtime/stageEnvironment.js +6 -1
- package/dist/runtime/stageProcessLauncher.js +23 -0
- package/dist/runtime/stageSecrets.d.ts +6 -1
- package/dist/runtime/stageSecrets.js +34 -1
- package/dist/server/agentAuthorRoutes.d.ts +5 -0
- package/dist/server/agentAuthorRoutes.js +64 -0
- package/dist/server/agentRoutes.d.ts +5 -0
- package/dist/server/agentRoutes.js +323 -0
- package/dist/server/bootstrap.d.ts +8 -0
- package/dist/server/bootstrap.js +36 -10
- package/dist/server/controlToken.js +8 -0
- package/dist/server/http.d.ts +8 -1
- package/dist/server/http.js +172 -20
- package/dist/server/mcpHost.js +1 -0
- package/dist/server/memoryRoutes.d.ts +5 -0
- package/dist/server/memoryRoutes.js +146 -0
- package/dist/server/projectMcpRoutes.d.ts +1 -0
- package/dist/server/projectMcpRoutes.js +241 -3
- package/dist/toolkit/guard.d.ts +27 -0
- package/dist/toolkit/guard.js +98 -0
- package/dist/toolkit/index.d.ts +48 -0
- package/dist/toolkit/index.js +82 -0
- package/dist/toolkit/meta.d.ts +36 -0
- package/dist/toolkit/meta.js +117 -0
- package/dist/toolkit/profiles.d.ts +13 -0
- package/dist/toolkit/profiles.js +25 -0
- package/dist/toolkit/record.d.ts +15 -0
- package/dist/toolkit/record.js +17 -0
- package/dist/tools/memoryTools.d.ts +95 -0
- package/dist/tools/memoryTools.js +179 -0
- package/dist/tools/readEmail.d.ts +3 -3
- package/dist/types/pipeline.d.ts +3 -0
- package/dist/types/stage.d.ts +2 -0
- package/dist/ui/assets/AssistantRuntimeProvider-CsiPFhCT.js +9 -0
- package/dist/ui/assets/MarkdownText-D7tYaIFO.js +29 -0
- package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +6 -0
- package/dist/ui/assets/Tooltip-DrpoRRNi.js +1 -0
- package/dist/ui/assets/chat-BbLukq9W.js +5 -0
- package/dist/ui/assets/chat-zIZU_bP1.css +2 -0
- package/dist/ui/assets/jsx-runtime-iVoFAvQ_.js +1 -0
- package/dist/ui/assets/{index-Clv4sJpU.css → main-BFo79krC.css} +1 -1
- package/dist/ui/assets/main-CijYMeM0.js +259 -0
- package/dist/ui/chat.html +25 -0
- package/dist/ui/index.html +6 -2
- package/dist/workshop/modelSettings.d.ts +2 -2
- package/dist/workshop/modelSettings.js +5 -11
- package/examples/README.md +1 -0
- package/examples/channels-smoke/README.md +12 -1
- package/examples/github-release/README.md +1 -1
- package/examples/memory/README.md +99 -0
- package/examples/memory/desk-outage.task.yaml +15 -0
- package/examples/memory/desk-refund.task.yaml +15 -0
- package/examples/memory/desk-revisit-outage.task.yaml +11 -0
- package/examples/memory/desk-revisit.pipeline.yaml +123 -0
- package/examples/memory/desk.pipeline.yaml +192 -0
- package/examples/memory/file-card.pipeline.yaml +39 -0
- package/examples/memory/file-ledger.task.yaml +22 -0
- package/examples/memory/file-release.task.yaml +24 -0
- package/examples/memory/file-rich.pipeline.yaml +40 -0
- package/examples/memory/file-ticket.task.yaml +7 -0
- package/examples/memory/file-timeline.task.yaml +28 -0
- package/examples/memory/find-card.pipeline.yaml +46 -0
- package/examples/memory/find-ticket.task.yaml +7 -0
- package/examples/memory/missing.pipeline.yaml +16 -0
- package/examples/memory/recall.pipeline.yaml +24 -0
- package/examples/memory/recall.task.yaml +5 -0
- package/examples/memory/remember-ada.task.yaml +6 -0
- package/examples/memory/remember-grace.task.yaml +6 -0
- package/examples/memory/remember.pipeline.yaml +58 -0
- package/examples/memory/stageflow.yaml +12 -0
- package/examples/memory/update-card.pipeline.yaml +43 -0
- package/examples/memory/update-ledger.task.yaml +23 -0
- package/examples/memory/update-rich.pipeline.yaml +44 -0
- package/examples/memory/update-ticket.task.yaml +7 -0
- package/examples/stage-mcp/README.md +1 -1
- package/package.json +2 -1
- package/dist/ui/assets/index-BOhqnPNg.js +0 -260
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AgentService } from "../service.js";
|
|
2
|
+
import type { ListenerConnection } from "./inbound.js";
|
|
3
|
+
import type { ChannelListener, ListenerDeps, ListenerState } from "./listener.js";
|
|
4
|
+
import type { AgentInboundMessage } from "./port.js";
|
|
5
|
+
export type ListenerFactory = (connection: ListenerConnection, deps: ListenerDeps) => ChannelListener | undefined;
|
|
6
|
+
/** Listeners the Host can hold open itself. Other providers (Slack, Telegram) stay on webhooks. */
|
|
7
|
+
export declare const DEFAULT_FACTORIES: Record<string, ListenerFactory>;
|
|
8
|
+
/**
|
|
9
|
+
* Keeps one listener per connection that an enabled agent answers on: starts it when the agent is enabled or
|
|
10
|
+
* linked, restarts it when the connection's settings change, stops it when no enabled agent uses it.
|
|
11
|
+
* `reconcile` is cheap and idempotent, so it runs on every agent change and on a timer.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ChannelSupervisor {
|
|
14
|
+
private readonly options;
|
|
15
|
+
private readonly running;
|
|
16
|
+
private chain;
|
|
17
|
+
private timer;
|
|
18
|
+
private stopped;
|
|
19
|
+
private readonly warned;
|
|
20
|
+
constructor(options: {
|
|
21
|
+
service: Pick<AgentService, "list" | "onChange">;
|
|
22
|
+
projectRoot: string;
|
|
23
|
+
resolve: (connectionId: string) => ListenerConnection | undefined;
|
|
24
|
+
deliver: (message: AgentInboundMessage) => Promise<unknown>;
|
|
25
|
+
log: (message: string) => void;
|
|
26
|
+
factories?: Record<string, ListenerFactory>;
|
|
27
|
+
intervalMs?: number;
|
|
28
|
+
});
|
|
29
|
+
/** Start following agents: listeners for what is linked now, and again after every change. */
|
|
30
|
+
start(): void;
|
|
31
|
+
reconcile(): Promise<void>;
|
|
32
|
+
private run;
|
|
33
|
+
/** The state of the listener on a connection, or undefined when none runs (webhook providers, no enabled agent). */
|
|
34
|
+
status(connectionId: string): ListenerState | undefined;
|
|
35
|
+
stop(): Promise<void>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { channelIdentity } from "./identity.js";
|
|
3
|
+
import { createAgentMailListener, sdkAgentMailTransport } from "./agentmailListener.js";
|
|
4
|
+
import { createIMessageListener, sdkIMessageTransport } from "./imessageListener.js";
|
|
5
|
+
/** Listeners the Host can hold open itself. Other providers (Slack, Telegram) stay on webhooks. */
|
|
6
|
+
export const DEFAULT_FACTORIES = {
|
|
7
|
+
agentmail: (connection, deps) => {
|
|
8
|
+
const config = connection.config;
|
|
9
|
+
const apiKey = connection.secrets.apiKey;
|
|
10
|
+
if (!config.inbox || !apiKey)
|
|
11
|
+
return undefined;
|
|
12
|
+
return createAgentMailListener({ connectionId: connection.id, inbox: config.inbox }, sdkAgentMailTransport({ apiKey, region: config.region ?? "us", inbox: config.inbox }), deps);
|
|
13
|
+
},
|
|
14
|
+
imessage: (connection, deps) => {
|
|
15
|
+
const secrets = connection.credential?.secrets;
|
|
16
|
+
if (!secrets?.projectId || !secrets.projectSecret)
|
|
17
|
+
return undefined;
|
|
18
|
+
return createIMessageListener({ connectionId: connection.id }, sdkIMessageTransport({ projectId: secrets.projectId, projectSecret: secrets.projectSecret }), deps);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
const fingerprintOf = (connection) => createHash("sha256").update(JSON.stringify([connection.provider, connection.config, connection.secrets, connection.credential?.secrets])).digest("hex");
|
|
22
|
+
/**
|
|
23
|
+
* Keeps one listener per connection that an enabled agent answers on: starts it when the agent is enabled or
|
|
24
|
+
* linked, restarts it when the connection's settings change, stops it when no enabled agent uses it.
|
|
25
|
+
* `reconcile` is cheap and idempotent, so it runs on every agent change and on a timer.
|
|
26
|
+
*/
|
|
27
|
+
export class ChannelSupervisor {
|
|
28
|
+
options;
|
|
29
|
+
running = new Map();
|
|
30
|
+
chain = Promise.resolve();
|
|
31
|
+
timer;
|
|
32
|
+
stopped = false;
|
|
33
|
+
warned = new Set();
|
|
34
|
+
constructor(options) {
|
|
35
|
+
this.options = options;
|
|
36
|
+
}
|
|
37
|
+
/** Start following agents: listeners for what is linked now, and again after every change. */
|
|
38
|
+
start() {
|
|
39
|
+
this.options.service.onChange(() => void this.reconcile());
|
|
40
|
+
void this.reconcile();
|
|
41
|
+
this.timer = setInterval(() => void this.reconcile(), this.options.intervalMs ?? 60_000);
|
|
42
|
+
this.timer.unref?.();
|
|
43
|
+
}
|
|
44
|
+
reconcile() {
|
|
45
|
+
this.chain = this.chain.then(() => this.run()).catch((error) => this.options.log(`channel listeners: ${error instanceof Error ? error.message : String(error)}`));
|
|
46
|
+
return this.chain;
|
|
47
|
+
}
|
|
48
|
+
async run() {
|
|
49
|
+
if (this.stopped)
|
|
50
|
+
return;
|
|
51
|
+
const agents = await this.options.service.list(this.options.projectRoot);
|
|
52
|
+
const wanted = new Set(agents.filter((agent) => agent.enabled && agent.channelConnection).map((agent) => agent.channelConnection));
|
|
53
|
+
for (const [id, entry] of [...this.running]) {
|
|
54
|
+
const connection = wanted.has(id) ? this.options.resolve(id) : undefined;
|
|
55
|
+
if (connection && fingerprintOf(connection) === entry.fingerprint)
|
|
56
|
+
continue;
|
|
57
|
+
await entry.listener.stop().catch(() => undefined);
|
|
58
|
+
this.running.delete(id);
|
|
59
|
+
}
|
|
60
|
+
for (const id of [...wanted].sort()) {
|
|
61
|
+
if (this.running.has(id) || this.stopped)
|
|
62
|
+
continue;
|
|
63
|
+
const connection = this.options.resolve(id);
|
|
64
|
+
const factory = connection ? (this.options.factories ?? DEFAULT_FACTORIES)[connection.provider] : undefined;
|
|
65
|
+
if (!connection || !factory)
|
|
66
|
+
continue;
|
|
67
|
+
// Two connections can point at one inbox; a second stream would deliver every message twice.
|
|
68
|
+
const identity = channelIdentity(connection);
|
|
69
|
+
const holder = [...this.running].find(([, entry]) => entry.identity === identity)?.[0];
|
|
70
|
+
if (holder) {
|
|
71
|
+
if (!this.warned.has(id))
|
|
72
|
+
this.options.log(`channel listeners: ${id} reaches the same inbox or line as ${holder}; only ${holder} is listened to`);
|
|
73
|
+
this.warned.add(id);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
this.warned.delete(id);
|
|
77
|
+
const listener = factory(connection, { onMessage: async (message) => void (await this.options.deliver(message)), log: this.options.log });
|
|
78
|
+
if (!listener)
|
|
79
|
+
continue;
|
|
80
|
+
this.running.set(id, { listener, fingerprint: fingerprintOf(connection), identity });
|
|
81
|
+
await listener.start();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** The state of the listener on a connection, or undefined when none runs (webhook providers, no enabled agent). */
|
|
85
|
+
status(connectionId) {
|
|
86
|
+
return this.running.get(connectionId)?.listener.state();
|
|
87
|
+
}
|
|
88
|
+
async stop() {
|
|
89
|
+
this.stopped = true;
|
|
90
|
+
if (this.timer)
|
|
91
|
+
clearInterval(this.timer);
|
|
92
|
+
await this.chain.catch(() => undefined);
|
|
93
|
+
await Promise.all([...this.running.values()].map((entry) => entry.listener.stop().catch(() => undefined)));
|
|
94
|
+
this.running.clear();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { AgentInboundMessage } from "./port.js";
|
|
2
|
+
export type TelegramInboundConfig = {
|
|
3
|
+
connectionId: string;
|
|
4
|
+
secretToken?: string;
|
|
5
|
+
};
|
|
6
|
+
export type TelegramParseResult = {
|
|
7
|
+
ok: true;
|
|
8
|
+
message: AgentInboundMessage;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
code: "agent.signature_invalid" | "agent.invalid";
|
|
12
|
+
};
|
|
13
|
+
export declare function verifyTelegramSecret(config: TelegramInboundConfig, headerToken: string | undefined): {
|
|
14
|
+
ok: true;
|
|
15
|
+
} | {
|
|
16
|
+
ok: false;
|
|
17
|
+
code: "agent.signature_invalid";
|
|
18
|
+
};
|
|
19
|
+
export declare function parseTelegramInbound(config: TelegramInboundConfig, payload: unknown): TelegramParseResult;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
export function verifyTelegramSecret(config, headerToken) {
|
|
3
|
+
if (config.secretToken === undefined)
|
|
4
|
+
return { ok: true };
|
|
5
|
+
if (headerToken === undefined)
|
|
6
|
+
return { ok: false, code: "agent.signature_invalid" };
|
|
7
|
+
const left = Buffer.from(config.secretToken);
|
|
8
|
+
const right = Buffer.from(headerToken);
|
|
9
|
+
if (left.length !== right.length || !timingSafeEqual(left, right)) {
|
|
10
|
+
return { ok: false, code: "agent.signature_invalid" };
|
|
11
|
+
}
|
|
12
|
+
return { ok: true };
|
|
13
|
+
}
|
|
14
|
+
export function parseTelegramInbound(config, payload) {
|
|
15
|
+
if (typeof payload !== "object" || payload === null)
|
|
16
|
+
return { ok: false, code: "agent.invalid" };
|
|
17
|
+
const message = payload.message;
|
|
18
|
+
if (typeof message !== "object" || message === null)
|
|
19
|
+
return { ok: false, code: "agent.invalid" };
|
|
20
|
+
const record = message;
|
|
21
|
+
const text = typeof record.text === "string" ? record.text.trim() : "";
|
|
22
|
+
if (text.length === 0)
|
|
23
|
+
return { ok: false, code: "agent.invalid" };
|
|
24
|
+
const chat = record.chat;
|
|
25
|
+
if (typeof chat !== "object" || chat === null)
|
|
26
|
+
return { ok: false, code: "agent.invalid" };
|
|
27
|
+
const chatId = chat.id;
|
|
28
|
+
if (typeof chatId !== "number" && typeof chatId !== "string") {
|
|
29
|
+
return { ok: false, code: "agent.invalid" };
|
|
30
|
+
}
|
|
31
|
+
const messageId = record.message_id;
|
|
32
|
+
if (typeof messageId !== "number" || !Number.isFinite(messageId)) {
|
|
33
|
+
return { ok: false, code: "agent.invalid" };
|
|
34
|
+
}
|
|
35
|
+
const from = record.from;
|
|
36
|
+
const fromLabel = typeof from === "object" && from !== null && typeof from.username === "string"
|
|
37
|
+
? from.username
|
|
38
|
+
: undefined;
|
|
39
|
+
const threadId = String(chatId);
|
|
40
|
+
return {
|
|
41
|
+
ok: true,
|
|
42
|
+
message: {
|
|
43
|
+
provider: "telegram",
|
|
44
|
+
connectionId: config.connectionId,
|
|
45
|
+
eventId: `telegram:${messageId}:${threadId}`,
|
|
46
|
+
threadId,
|
|
47
|
+
replyTo: threadId,
|
|
48
|
+
text,
|
|
49
|
+
...(fromLabel !== undefined ? { from: fromLabel } : {}),
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type AgentDefinition } from "../config/loadAgent.js";
|
|
2
|
+
export type SummaryLine = {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Best-effort view of a possibly incomplete draft with schema defaults
|
|
8
|
+
* applied, so a partial draft can still be described. Required strings that
|
|
9
|
+
* are missing become empty; everything else gets its default.
|
|
10
|
+
*/
|
|
11
|
+
export declare function withDefaults(draft: Record<string, unknown>): AgentDefinition;
|
|
12
|
+
/** One line per section that differs between two drafts, describing the new value. */
|
|
13
|
+
export declare function describeChanges(before: Record<string, unknown>, after: Record<string, unknown>): SummaryLine[];
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { agentDefinitionSchema, BUILTIN_TOOL_GROUPS } from "../config/loadAgent.js";
|
|
2
|
+
/**
|
|
3
|
+
* Best-effort view of a possibly incomplete draft with schema defaults
|
|
4
|
+
* applied, so a partial draft can still be described. Required strings that
|
|
5
|
+
* are missing become empty; everything else gets its default.
|
|
6
|
+
*/
|
|
7
|
+
export function withDefaults(draft) {
|
|
8
|
+
const lenient = { id: "draft", name: "draft", instructions: "draft", ...draft };
|
|
9
|
+
const parsed = agentDefinitionSchema.safeParse(lenient);
|
|
10
|
+
if (parsed.success)
|
|
11
|
+
return parsed.data;
|
|
12
|
+
// Fall back section by section so one bad field doesn't hide the rest.
|
|
13
|
+
const base = agentDefinitionSchema.parse({ id: "draft", name: "draft", instructions: "draft" });
|
|
14
|
+
const merged = { ...base };
|
|
15
|
+
for (const [key, value] of Object.entries(draft)) {
|
|
16
|
+
const attempt = agentDefinitionSchema.safeParse({ ...base, [key]: value });
|
|
17
|
+
if (attempt.success)
|
|
18
|
+
merged[key] = attempt.data[key];
|
|
19
|
+
}
|
|
20
|
+
return merged;
|
|
21
|
+
}
|
|
22
|
+
function list(items, empty) {
|
|
23
|
+
return items.length > 0 ? items.join(", ") : empty;
|
|
24
|
+
}
|
|
25
|
+
const SECTIONS = [
|
|
26
|
+
{
|
|
27
|
+
label: "Identity",
|
|
28
|
+
keys: ["id", "name", "description", "greeting"],
|
|
29
|
+
describe: (d) => [d.name, d.id].filter(Boolean).join(" · "),
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: "Instructions",
|
|
33
|
+
keys: ["instructions", "project_context"],
|
|
34
|
+
describe: (d) => {
|
|
35
|
+
const lines = d.instructions.split("\n").filter((line) => line.trim()).length;
|
|
36
|
+
return `${lines} line${lines === 1 ? "" : "s"}${d.project_context ? " · reads project context" : ""}`;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
label: "Model",
|
|
41
|
+
keys: ["model"],
|
|
42
|
+
describe: (d) => `${d.model.id ?? "project default"} · ${d.model.backend === "claude" ? "Claude" : "Pi"} · ${d.model.thinking} thinking`,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
label: "Tools",
|
|
46
|
+
keys: ["tools"],
|
|
47
|
+
describe: (d) => list([
|
|
48
|
+
...d.tools.builtin,
|
|
49
|
+
...d.tools.builtin_tools.filter((tool) => !d.tools.builtin.some((group) => BUILTIN_TOOL_GROUPS[group].includes(tool))),
|
|
50
|
+
...Object.entries(d.tools.mcp).map(([server, tools]) => `${server} (${tools.includes("*") ? "all" : tools.join(", ")})`),
|
|
51
|
+
...d.tools.skills.map((skill) => `skill ${skill}`),
|
|
52
|
+
...(d.tools.browser ? ["browser"] : []),
|
|
53
|
+
...d.tools.stageflow.groups.map((group) => `stageflow ${group}`),
|
|
54
|
+
...(d.tools.stageflow.tools.length > 0 ? [`stageflow ${d.tools.stageflow.tools.join(", ")}`] : []),
|
|
55
|
+
], "none"),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
label: "Approvals",
|
|
59
|
+
keys: ["approvals"],
|
|
60
|
+
describe: (d) => d.approvals.ask_first.length > 0
|
|
61
|
+
? `asks before ${d.approvals.ask_first.join(", ")}`
|
|
62
|
+
: "nothing asks first",
|
|
63
|
+
},
|
|
64
|
+
{ label: "Sub-agents", keys: ["sub_agents", "sub_agent_depth"], describe: (d) => list(d.sub_agents, "none") },
|
|
65
|
+
{
|
|
66
|
+
label: "Guardrails",
|
|
67
|
+
keys: ["guardrails", "evals"],
|
|
68
|
+
describe: (d) => `${d.guardrails.block_patterns.length} block pattern${d.guardrails.block_patterns.length === 1 ? "" : "s"}`,
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
label: "Capture",
|
|
72
|
+
keys: ["observability"],
|
|
73
|
+
describe: (d) => ({ off: "off", metadata: "timing and metadata only", full: "full content, secrets masked" })[d.observability.capture],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
label: "Channels",
|
|
77
|
+
keys: ["channel", "schedule"],
|
|
78
|
+
describe: (d) => list([...(d.channel ? [`${d.channel.connection_id} (${d.channel.allow_from.length === 0 ? "nobody allowed" : d.channel.allow_from.join(", ")})`] : []), ...(d.schedule ? [`schedule ${d.schedule.cron}`] : [])], "console only"),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
label: "Limits",
|
|
82
|
+
keys: ["limits"],
|
|
83
|
+
describe: (d) => `${d.limits.always_on ? "always on" : `${d.limits.session_minutes} min · ${d.limits.max_turns} turns`} · ${d.limits.cost_usd === null ? "no cost cap" : `$${d.limits.cost_usd}${d.limits.always_on ? " per day" : ""}`}`,
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
/** One line per section that differs between two drafts, describing the new value. */
|
|
87
|
+
export function describeChanges(before, after) {
|
|
88
|
+
const a = withDefaults(before);
|
|
89
|
+
const b = withDefaults(after);
|
|
90
|
+
return SECTIONS.filter((section) => section.keys.some((key) => JSON.stringify(a[key] ?? null) !== JSON.stringify(b[key] ?? null))).map((section) => ({ label: section.label, value: section.describe(b) }));
|
|
91
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { AgentDefinition } from "../config/loadAgent.js";
|
|
2
|
+
/** May `caller` (at nesting `depth`, 0 = top-level session) call `calleeId`? Throws when it may not. */
|
|
3
|
+
export declare function assertDelegateAllowed(caller: Pick<AgentDefinition, "sub_agents" | "sub_agent_depth">, calleeId: string, depth: number): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AgentError } from "./errors.js";
|
|
2
|
+
/** May `caller` (at nesting `depth`, 0 = top-level session) call `calleeId`? Throws when it may not. */
|
|
3
|
+
export function assertDelegateAllowed(caller, calleeId, depth) {
|
|
4
|
+
if (!caller.sub_agents.includes(calleeId))
|
|
5
|
+
throw new AgentError("agent.delegate_not_allowed");
|
|
6
|
+
if (depth >= caller.sub_agent_depth)
|
|
7
|
+
throw new AgentError("agent.delegate_depth_exceeded");
|
|
8
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentIssue } from "../config/loadAgent.js";
|
|
2
|
+
export type AgentErrorCode = "agent.invalid" | "agent.not_found" | "agent.exists" | "agent.archived" | "agent.disabled" | "agent.conflict" | "agent.revision_not_found" | "agent.session_not_found" | "agent.session_busy" | "agent.tool_not_granted" | "agent.approval_not_required" | "agent.approval_not_pending" | "agent.approval_expired" | "agent.approval_forbidden" | "agent.unbound" | "agent.sender_not_allowed" | "agent.outbound_unknown" | "agent.trace_metadata_body" | "agent.guardrail_blocked" | "agent.delegate_not_allowed" | "agent.delegate_depth_exceeded" | "agent.sandbox_unavailable" | "agent.limit_reached" | "agent.model_timeout" | "agent.backend_unavailable" | "agent.approval_denied";
|
|
3
|
+
/** Domain failure with a stable code; the HTTP, CLI and MCP layers map it, they don't parse messages. */
|
|
4
|
+
export declare class AgentError extends Error {
|
|
5
|
+
readonly code: AgentErrorCode;
|
|
6
|
+
readonly issues: AgentIssue[];
|
|
7
|
+
constructor(code: AgentErrorCode, message?: string, issues?: AgentIssue[]);
|
|
8
|
+
get httpStatus(): number;
|
|
9
|
+
}
|
|
10
|
+
export declare function isAgentError(error: unknown): error is AgentError;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const STATUS = {
|
|
2
|
+
"agent.invalid": 422,
|
|
3
|
+
"agent.not_found": 404,
|
|
4
|
+
"agent.revision_not_found": 404,
|
|
5
|
+
"agent.session_not_found": 404,
|
|
6
|
+
"agent.exists": 409,
|
|
7
|
+
"agent.archived": 409,
|
|
8
|
+
"agent.disabled": 409,
|
|
9
|
+
"agent.conflict": 409,
|
|
10
|
+
"agent.session_busy": 409,
|
|
11
|
+
"agent.limit_reached": 409,
|
|
12
|
+
"agent.model_timeout": 504,
|
|
13
|
+
"agent.approval_forbidden": 403,
|
|
14
|
+
"agent.sender_not_allowed": 403,
|
|
15
|
+
};
|
|
16
|
+
/** Domain failure with a stable code; the HTTP, CLI and MCP layers map it, they don't parse messages. */
|
|
17
|
+
export class AgentError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
issues;
|
|
20
|
+
constructor(code, message, issues = []) {
|
|
21
|
+
super(message ?? code);
|
|
22
|
+
this.code = code;
|
|
23
|
+
this.issues = issues;
|
|
24
|
+
this.name = "AgentError";
|
|
25
|
+
}
|
|
26
|
+
get httpStatus() {
|
|
27
|
+
return STATUS[this.code] ?? 400;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function isAgentError(error) {
|
|
31
|
+
return error instanceof AgentError;
|
|
32
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AgentGuardrails } from "../config/loadAgent.js";
|
|
2
|
+
export type GuardrailResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
} | {
|
|
5
|
+
ok: false;
|
|
6
|
+
pattern: string;
|
|
7
|
+
};
|
|
8
|
+
/** Block patterns are validated as regular expressions when the definition is parsed. */
|
|
9
|
+
export declare function checkGuardrails(guardrails: AgentGuardrails, text: string): GuardrailResult;
|
|
10
|
+
/**
|
|
11
|
+
* The one path model output takes to a person. Without block patterns, deltas go straight through. With them, a
|
|
12
|
+
* pattern can match text that has not been written yet, so deltas are held and released only once the finished reply
|
|
13
|
+
* (and everything held) has passed the check; a blocked reply is never streamed. The cost is that guarded agents show
|
|
14
|
+
* their reply at the end instead of word by word.
|
|
15
|
+
*/
|
|
16
|
+
export type GuardedStream = {
|
|
17
|
+
/** Give this to the model runtime. */
|
|
18
|
+
push(delta: string): void;
|
|
19
|
+
/** The check on the finished reply passed: let held text out. Returns the verdict; nothing is released when it fails. */
|
|
20
|
+
release(finalText: string): GuardrailResult;
|
|
21
|
+
/** The turn ended without a reply to show: drop what was held. */
|
|
22
|
+
discard(): void;
|
|
23
|
+
};
|
|
24
|
+
export declare function guardedStream(guardrails: AgentGuardrails, forward: ((text: string) => void) | undefined): GuardedStream;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Block patterns are validated as regular expressions when the definition is parsed. */
|
|
2
|
+
export function checkGuardrails(guardrails, text) {
|
|
3
|
+
for (const pattern of guardrails.block_patterns) {
|
|
4
|
+
if (new RegExp(pattern).test(text))
|
|
5
|
+
return { ok: false, pattern };
|
|
6
|
+
}
|
|
7
|
+
return { ok: true };
|
|
8
|
+
}
|
|
9
|
+
export function guardedStream(guardrails, forward) {
|
|
10
|
+
if (guardrails.block_patterns.length === 0) {
|
|
11
|
+
return { push: (delta) => forward?.(delta), release: () => ({ ok: true }), discard: () => undefined };
|
|
12
|
+
}
|
|
13
|
+
let held = [];
|
|
14
|
+
return {
|
|
15
|
+
push: (delta) => {
|
|
16
|
+
held.push(delta);
|
|
17
|
+
},
|
|
18
|
+
release(finalText) {
|
|
19
|
+
const verdict = checkGuardrails(guardrails, finalText);
|
|
20
|
+
if (!verdict.ok) {
|
|
21
|
+
held = [];
|
|
22
|
+
return verdict;
|
|
23
|
+
}
|
|
24
|
+
const streamed = checkGuardrails(guardrails, held.join(""));
|
|
25
|
+
if (!streamed.ok) {
|
|
26
|
+
held = [];
|
|
27
|
+
return streamed;
|
|
28
|
+
}
|
|
29
|
+
const out = held;
|
|
30
|
+
held = [];
|
|
31
|
+
for (const delta of out)
|
|
32
|
+
forward?.(delta);
|
|
33
|
+
return { ok: true };
|
|
34
|
+
},
|
|
35
|
+
discard() {
|
|
36
|
+
held = [];
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentDefinition } from "../config/loadAgent.js";
|
|
2
|
+
import type { ConversationMessage } from "./runtime/types.js";
|
|
3
|
+
/** Characters of replayed history a restarted session is given (about 15k tokens). */
|
|
4
|
+
export declare const HISTORY_CHAR_BUDGET = 60000;
|
|
5
|
+
/**
|
|
6
|
+
* Apply `limits.long_context` when a transcript is replayed into a new model
|
|
7
|
+
* session: `truncate` drops the oldest messages; `summarize` condenses them to
|
|
8
|
+
* one line each so the thread is still visible. The newest message is always kept.
|
|
9
|
+
*/
|
|
10
|
+
export declare function fitHistory(messages: readonly ConversationMessage[], policy: AgentDefinition["limits"]["long_context"], budget?: number): ConversationMessage[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Characters of replayed history a restarted session is given (about 15k tokens). */
|
|
2
|
+
export const HISTORY_CHAR_BUDGET = 60_000;
|
|
3
|
+
/**
|
|
4
|
+
* Apply `limits.long_context` when a transcript is replayed into a new model
|
|
5
|
+
* session: `truncate` drops the oldest messages; `summarize` condenses them to
|
|
6
|
+
* one line each so the thread is still visible. The newest message is always kept.
|
|
7
|
+
*/
|
|
8
|
+
export function fitHistory(messages, policy, budget = HISTORY_CHAR_BUDGET) {
|
|
9
|
+
const total = messages.reduce((sum, m) => sum + m.text.length, 0);
|
|
10
|
+
if (total <= budget || messages.length <= 1)
|
|
11
|
+
return [...messages];
|
|
12
|
+
const kept = [];
|
|
13
|
+
let used = 0;
|
|
14
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
15
|
+
const message = messages[i];
|
|
16
|
+
if (kept.length > 0 && used + message.text.length > budget)
|
|
17
|
+
break;
|
|
18
|
+
kept.unshift(message);
|
|
19
|
+
used += message.text.length;
|
|
20
|
+
}
|
|
21
|
+
const dropped = messages.slice(0, messages.length - kept.length);
|
|
22
|
+
if (policy === "truncate" || dropped.length === 0)
|
|
23
|
+
return kept;
|
|
24
|
+
const digest = dropped.map((m) => `- ${m.role}: ${m.text.replace(/\s+/g, " ").trim().slice(0, 160)}`).join("\n");
|
|
25
|
+
return [{ role: "assistant", text: `Earlier in this conversation (condensed):\n${digest}` }, ...kept];
|
|
26
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type Database from "better-sqlite3";
|
|
2
|
+
import type { ChannelService } from "../channels/service.js";
|
|
3
|
+
import { AgentInboundRouter } from "./communications/inbound.js";
|
|
4
|
+
import { ReplyDelivery } from "./communications/delivery.js";
|
|
5
|
+
import { ChannelSupervisor } from "./communications/supervisor.js";
|
|
6
|
+
import { AgentChatController } from "./chatTurn.js";
|
|
7
|
+
import { type OtlpSink } from "./otlpSink.js";
|
|
8
|
+
import type { ContactInfo } from "../channels/types.js";
|
|
9
|
+
import type { McpToolDeps } from "../mcp/deps.js";
|
|
10
|
+
import { AgentService, type AgentEnvironment } from "./service.js";
|
|
11
|
+
import type { ConversationBackend } from "./sessions.js";
|
|
12
|
+
import { PublicWebChat } from "./webChat/publicChat.js";
|
|
13
|
+
export type AgentHostContext = {
|
|
14
|
+
service: AgentService;
|
|
15
|
+
inbound: AgentInboundRouter;
|
|
16
|
+
publicChat: PublicWebChat;
|
|
17
|
+
chat: AgentChatController;
|
|
18
|
+
backend: ConversationBackend;
|
|
19
|
+
/** Streams held open to AgentMail and iMessage; absent unless the Host listens (not in tests). */
|
|
20
|
+
channelListeners?: ChannelSupervisor;
|
|
21
|
+
/** Replies to people on channels: retries, resend, mark delivered. */
|
|
22
|
+
delivery: ReplyDelivery;
|
|
23
|
+
/** How people reach a connection (the number to text), cached for a minute. */
|
|
24
|
+
channelContact(connectionId: string): Promise<{
|
|
25
|
+
provider: string;
|
|
26
|
+
contact: ContactInfo;
|
|
27
|
+
} | undefined>;
|
|
28
|
+
/** Stop what the Host started for agents (listeners). */
|
|
29
|
+
stop(): Promise<void>;
|
|
30
|
+
};
|
|
31
|
+
/** Read-only lookups the editor warnings use: `.mcp.json`, skills, and channel connections. */
|
|
32
|
+
export declare function createAgentEnvironment(options: {
|
|
33
|
+
agentDir: string;
|
|
34
|
+
cwd: string;
|
|
35
|
+
channels?: Pick<ChannelService, "list">;
|
|
36
|
+
}): AgentEnvironment;
|
|
37
|
+
/**
|
|
38
|
+
* Agent runtime for one Host. Agent state shares the Host's SQLite connection
|
|
39
|
+
* (migration 013). Turns left running by a previous process are failed here,
|
|
40
|
+
* since nothing can resume them.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createAgentHostContext(options: {
|
|
43
|
+
cwd: string;
|
|
44
|
+
agentDir: string;
|
|
45
|
+
connection: Database.Database;
|
|
46
|
+
channels?: Pick<ChannelService, "list">;
|
|
47
|
+
backend?: ConversationBackend;
|
|
48
|
+
environment?: AgentEnvironment;
|
|
49
|
+
otlpSink?: OtlpSink | undefined;
|
|
50
|
+
/** Host services the Stageflow tools need; agent services are added here. Without it agents get no Stageflow tools. */
|
|
51
|
+
/** Hold streams open to AgentMail and iMessage for agents linked to them. Only a running Host does this. */
|
|
52
|
+
listenOnChannels?: boolean;
|
|
53
|
+
toolkitDeps?: Pick<McpToolDeps, "manager" | "store" | "agentDir" | "providerAuthContext" | "projectRoot" | "providerBoot">;
|
|
54
|
+
}): AgentHostContext;
|