@dobby.ai/dobby 0.1.0 → 0.1.2
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 +84 -39
- package/dist/src/agent/event-forwarder.js +185 -16
- package/dist/src/cli/commands/cron.js +39 -35
- package/dist/src/cli/commands/doctor.js +81 -2
- package/dist/src/cli/commands/extension.js +3 -1
- package/dist/src/cli/commands/init.js +43 -173
- package/dist/src/cli/commands/topology.js +38 -14
- package/dist/src/cli/program.js +15 -137
- package/dist/src/cli/shared/config-io.js +3 -31
- package/dist/src/cli/shared/config-mutators.js +33 -9
- package/dist/src/cli/shared/configure-sections.js +52 -12
- package/dist/src/cli/shared/init-catalog.js +89 -46
- package/dist/src/cli/shared/local-extension-specs.js +85 -0
- package/dist/src/cli/shared/schema-prompts.js +26 -2
- package/dist/src/core/gateway.js +3 -1
- package/dist/src/core/routing.js +53 -38
- package/dist/src/core/types.js +2 -0
- package/dist/src/cron/config.js +2 -2
- package/dist/src/cron/service.js +87 -23
- package/dist/src/cron/store.js +1 -1
- package/dist/src/main.js +0 -0
- package/dist/src/shared/dobby-repo.js +40 -0
- package/package.json +11 -4
- package/.env.example +0 -9
- package/AGENTS.md +0 -267
- package/ROADMAP.md +0 -34
- package/config/cron.example.json +0 -9
- package/config/gateway.example.json +0 -128
- package/config/models.custom.example.json +0 -27
- package/dist/src/agent/tests/event-forwarder.test.js +0 -113
- package/dist/src/cli/shared/config-path.js +0 -207
- package/dist/src/cli/shared/init-models-file.js +0 -65
- package/dist/src/cli/shared/presets.js +0 -86
- package/dist/src/cli/tests/config-command.test.js +0 -42
- package/dist/src/cli/tests/config-io.test.js +0 -64
- package/dist/src/cli/tests/config-mutators.test.js +0 -47
- package/dist/src/cli/tests/config-path.test.js +0 -21
- package/dist/src/cli/tests/discord-config.test.js +0 -23
- package/dist/src/cli/tests/doctor.test.js +0 -107
- package/dist/src/cli/tests/init-catalog.test.js +0 -87
- package/dist/src/cli/tests/presets.test.js +0 -41
- package/dist/src/cli/tests/program-options.test.js +0 -92
- package/dist/src/cli/tests/routing-config.test.js +0 -199
- package/dist/src/cli/tests/routing-legacy.test.js +0 -191
- package/dist/src/core/tests/control-command.test.js +0 -17
- package/dist/src/core/tests/gateway-update-strategy.test.js +0 -167
- package/dist/src/core/tests/runtime-registry.test.js +0 -116
- package/dist/src/core/tests/typing-controller.test.js +0 -103
- package/docs/BOXLITE_SANDBOX_FEASIBILITY.md +0 -175
- package/docs/CRON_SCHEDULER_DESIGN.md +0 -374
- package/docs/DOCKER_SANDBOX_vs_BOXLITE.md +0 -77
- package/docs/EXTENSION_SYSTEM_ARCHITECTURE.md +0 -119
- package/docs/MVP.md +0 -135
- package/docs/RUNBOOK.md +0 -242
- package/docs/TEAMWORK_HANDOFF_DESIGN.md +0 -440
- package/plugins/connector-discord/dobby.manifest.json +0 -18
- package/plugins/connector-discord/index.js +0 -1
- package/plugins/connector-discord/package-lock.json +0 -360
- package/plugins/connector-discord/package.json +0 -38
- package/plugins/connector-discord/src/connector.ts +0 -350
- package/plugins/connector-discord/src/contribution.ts +0 -21
- package/plugins/connector-discord/src/mapper.ts +0 -102
- package/plugins/connector-discord/tsconfig.json +0 -19
- package/plugins/connector-feishu/dobby.manifest.json +0 -18
- package/plugins/connector-feishu/index.js +0 -1
- package/plugins/connector-feishu/package-lock.json +0 -618
- package/plugins/connector-feishu/package.json +0 -38
- package/plugins/connector-feishu/src/connector.ts +0 -343
- package/plugins/connector-feishu/src/contribution.ts +0 -26
- package/plugins/connector-feishu/src/mapper.ts +0 -401
- package/plugins/connector-feishu/tsconfig.json +0 -19
- package/plugins/plugin-sdk/index.d.ts +0 -261
- package/plugins/plugin-sdk/index.js +0 -1
- package/plugins/plugin-sdk/package-lock.json +0 -12
- package/plugins/plugin-sdk/package.json +0 -22
- package/plugins/provider-claude/dobby.manifest.json +0 -17
- package/plugins/provider-claude/index.js +0 -1
- package/plugins/provider-claude/package-lock.json +0 -3398
- package/plugins/provider-claude/package.json +0 -39
- package/plugins/provider-claude/src/contribution.ts +0 -1018
- package/plugins/provider-claude/tsconfig.json +0 -19
- package/plugins/provider-claude-cli/dobby.manifest.json +0 -17
- package/plugins/provider-claude-cli/index.js +0 -1
- package/plugins/provider-claude-cli/package-lock.json +0 -2898
- package/plugins/provider-claude-cli/package.json +0 -38
- package/plugins/provider-claude-cli/src/contribution.ts +0 -1673
- package/plugins/provider-claude-cli/tsconfig.json +0 -19
- package/plugins/provider-pi/dobby.manifest.json +0 -17
- package/plugins/provider-pi/index.js +0 -1
- package/plugins/provider-pi/package-lock.json +0 -3877
- package/plugins/provider-pi/package.json +0 -40
- package/plugins/provider-pi/src/contribution.ts +0 -476
- package/plugins/provider-pi/tsconfig.json +0 -19
- package/plugins/sandbox-core/boxlite.js +0 -1
- package/plugins/sandbox-core/dobby.manifest.json +0 -17
- package/plugins/sandbox-core/docker.js +0 -1
- package/plugins/sandbox-core/package-lock.json +0 -136
- package/plugins/sandbox-core/package.json +0 -39
- package/plugins/sandbox-core/src/boxlite-context.ts +0 -2
- package/plugins/sandbox-core/src/boxlite-contribution.ts +0 -53
- package/plugins/sandbox-core/src/boxlite-executor.ts +0 -911
- package/plugins/sandbox-core/src/docker-contribution.ts +0 -43
- package/plugins/sandbox-core/src/docker-executor.ts +0 -217
- package/plugins/sandbox-core/tsconfig.json +0 -19
- package/scripts/local-extensions.mjs +0 -168
- package/src/agent/event-forwarder.ts +0 -414
- package/src/cli/commands/config.ts +0 -328
- package/src/cli/commands/configure.ts +0 -92
- package/src/cli/commands/cron.ts +0 -410
- package/src/cli/commands/doctor.ts +0 -230
- package/src/cli/commands/extension.ts +0 -205
- package/src/cli/commands/init.ts +0 -396
- package/src/cli/commands/start.ts +0 -223
- package/src/cli/commands/topology.ts +0 -383
- package/src/cli/index.ts +0 -9
- package/src/cli/program.ts +0 -465
- package/src/cli/shared/config-io.ts +0 -277
- package/src/cli/shared/config-mutators.ts +0 -440
- package/src/cli/shared/config-schema.ts +0 -228
- package/src/cli/shared/config-types.ts +0 -121
- package/src/cli/shared/configure-sections.ts +0 -551
- package/src/cli/shared/discord-config.ts +0 -14
- package/src/cli/shared/init-catalog.ts +0 -189
- package/src/cli/shared/init-models-file.ts +0 -77
- package/src/cli/shared/runtime.ts +0 -33
- package/src/cli/shared/schema-prompts.ts +0 -414
- package/src/cli/tests/config-command.test.ts +0 -56
- package/src/cli/tests/config-io.test.ts +0 -92
- package/src/cli/tests/config-mutators.test.ts +0 -59
- package/src/cli/tests/doctor.test.ts +0 -120
- package/src/cli/tests/init-catalog.test.ts +0 -96
- package/src/cli/tests/program-options.test.ts +0 -113
- package/src/cli/tests/routing-config.test.ts +0 -209
- package/src/core/control-command.ts +0 -12
- package/src/core/dedup-store.ts +0 -103
- package/src/core/gateway.ts +0 -607
- package/src/core/routing.ts +0 -379
- package/src/core/runtime-registry.ts +0 -141
- package/src/core/tests/control-command.test.ts +0 -20
- package/src/core/tests/runtime-registry.test.ts +0 -140
- package/src/core/tests/typing-controller.test.ts +0 -129
- package/src/core/types.ts +0 -318
- package/src/core/typing-controller.ts +0 -119
- package/src/cron/config.ts +0 -154
- package/src/cron/schedule.ts +0 -61
- package/src/cron/service.ts +0 -249
- package/src/cron/store.ts +0 -155
- package/src/cron/types.ts +0 -60
- package/src/extension/loader.ts +0 -145
- package/src/extension/manager.ts +0 -355
- package/src/extension/manifest.ts +0 -26
- package/src/extension/registry.ts +0 -229
- package/src/main.ts +0 -8
- package/src/sandbox/executor.ts +0 -44
- package/src/sandbox/host-executor.ts +0 -118
- package/tsconfig.json +0 -18
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import { setTimeout as delay } from "node:timers/promises";
|
|
3
|
-
import test from "node:test";
|
|
4
|
-
import { createTypingKeepAliveController } from "../typing-controller.js";
|
|
5
|
-
import type {
|
|
6
|
-
ConnectorPlugin,
|
|
7
|
-
GatewayLogger,
|
|
8
|
-
InboundEnvelope,
|
|
9
|
-
} from "../types.js";
|
|
10
|
-
|
|
11
|
-
function createLogger(): GatewayLogger {
|
|
12
|
-
return {
|
|
13
|
-
error() {},
|
|
14
|
-
warn() {},
|
|
15
|
-
info() {},
|
|
16
|
-
debug() {},
|
|
17
|
-
} as unknown as GatewayLogger;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function createInbound(): InboundEnvelope {
|
|
21
|
-
return {
|
|
22
|
-
connectorId: "discord.main",
|
|
23
|
-
platform: "discord",
|
|
24
|
-
accountId: "discord.main",
|
|
25
|
-
source: {
|
|
26
|
-
type: "channel",
|
|
27
|
-
id: "123",
|
|
28
|
-
},
|
|
29
|
-
chatId: "123",
|
|
30
|
-
messageId: "m-1",
|
|
31
|
-
userId: "u-1",
|
|
32
|
-
userName: "tester",
|
|
33
|
-
text: "hello",
|
|
34
|
-
attachments: [],
|
|
35
|
-
timestampMs: Date.now(),
|
|
36
|
-
raw: {},
|
|
37
|
-
isDirectMessage: false,
|
|
38
|
-
mentionedBot: true,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function createConnector(sentTyping: number[]): ConnectorPlugin {
|
|
43
|
-
return {
|
|
44
|
-
id: "discord.main",
|
|
45
|
-
platform: "discord",
|
|
46
|
-
name: "discord",
|
|
47
|
-
capabilities: {
|
|
48
|
-
updateStrategy: "edit",
|
|
49
|
-
supportedSources: ["channel"],
|
|
50
|
-
supportsThread: true,
|
|
51
|
-
supportsTyping: true,
|
|
52
|
-
supportsFileUpload: true,
|
|
53
|
-
maxTextLength: 2000,
|
|
54
|
-
},
|
|
55
|
-
async start() {},
|
|
56
|
-
async send() {
|
|
57
|
-
return { messageId: "reply-1" };
|
|
58
|
-
},
|
|
59
|
-
async sendTyping() {
|
|
60
|
-
sentTyping.push(Date.now());
|
|
61
|
-
},
|
|
62
|
-
async stop() {},
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
test("typing is sent before the first visible output when response is slow", async () => {
|
|
67
|
-
const sentTyping: number[] = [];
|
|
68
|
-
const controller = createTypingKeepAliveController(
|
|
69
|
-
createConnector(sentTyping),
|
|
70
|
-
createInbound(),
|
|
71
|
-
createLogger(),
|
|
72
|
-
{
|
|
73
|
-
initialDelayMs: 0,
|
|
74
|
-
keepaliveIntervalMs: 200,
|
|
75
|
-
},
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
await controller.prime();
|
|
80
|
-
assert.equal(sentTyping.length, 1);
|
|
81
|
-
} finally {
|
|
82
|
-
controller.stop();
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("visible output before prime suppresses typing", async () => {
|
|
87
|
-
const sentTyping: number[] = [];
|
|
88
|
-
const controller = createTypingKeepAliveController(
|
|
89
|
-
createConnector(sentTyping),
|
|
90
|
-
createInbound(),
|
|
91
|
-
createLogger(),
|
|
92
|
-
{
|
|
93
|
-
initialDelayMs: 0,
|
|
94
|
-
keepaliveIntervalMs: 200,
|
|
95
|
-
},
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
controller.markVisibleOutput();
|
|
100
|
-
await controller.prime();
|
|
101
|
-
assert.deepEqual(sentTyping, []);
|
|
102
|
-
} finally {
|
|
103
|
-
controller.stop();
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("visible output stops further typing keepalive", async () => {
|
|
108
|
-
const sentTyping: number[] = [];
|
|
109
|
-
const controller = createTypingKeepAliveController(
|
|
110
|
-
createConnector(sentTyping),
|
|
111
|
-
createInbound(),
|
|
112
|
-
createLogger(),
|
|
113
|
-
{
|
|
114
|
-
initialDelayMs: 0,
|
|
115
|
-
keepaliveIntervalMs: 15,
|
|
116
|
-
},
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
await controller.prime();
|
|
121
|
-
const beforeVisibleOutput = sentTyping.length;
|
|
122
|
-
assert.equal(beforeVisibleOutput > 0, true);
|
|
123
|
-
controller.markVisibleOutput();
|
|
124
|
-
await delay(30);
|
|
125
|
-
assert.equal(sentTyping.length, beforeVisibleOutput);
|
|
126
|
-
} finally {
|
|
127
|
-
controller.stop();
|
|
128
|
-
}
|
|
129
|
-
});
|
package/src/core/types.ts
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
import type { ImageContent } from "@mariozechner/pi-ai";
|
|
2
|
-
import type { Logger } from "pino";
|
|
3
|
-
import type { Executor } from "../sandbox/executor.js";
|
|
4
|
-
|
|
5
|
-
export type Platform = string;
|
|
6
|
-
export type ToolProfile = "full" | "readonly";
|
|
7
|
-
export type MentionPolicy = "required" | "optional";
|
|
8
|
-
export type BindingSourceType = "channel" | "chat";
|
|
9
|
-
export type ExtensionKind = "provider" | "connector" | "sandbox";
|
|
10
|
-
export type ExtensionApiVersion = "1.0";
|
|
11
|
-
export const BUILTIN_HOST_SANDBOX_ID = "host.builtin";
|
|
12
|
-
|
|
13
|
-
export interface InboundAttachment {
|
|
14
|
-
id: string;
|
|
15
|
-
fileName?: string;
|
|
16
|
-
mimeType?: string;
|
|
17
|
-
size?: number;
|
|
18
|
-
localPath?: string;
|
|
19
|
-
remoteUrl?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface BindingSource {
|
|
23
|
-
type: BindingSourceType;
|
|
24
|
-
id: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface InboundEnvelope {
|
|
28
|
-
connectorId: string;
|
|
29
|
-
platform: Platform;
|
|
30
|
-
accountId: string;
|
|
31
|
-
guildId?: string;
|
|
32
|
-
source: BindingSource;
|
|
33
|
-
chatId: string;
|
|
34
|
-
threadId?: string;
|
|
35
|
-
messageId: string;
|
|
36
|
-
userId: string;
|
|
37
|
-
userName?: string;
|
|
38
|
-
text: string;
|
|
39
|
-
attachments: InboundAttachment[];
|
|
40
|
-
timestampMs: number;
|
|
41
|
-
raw: unknown;
|
|
42
|
-
isDirectMessage: boolean;
|
|
43
|
-
mentionedBot: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface OutboundAttachment {
|
|
47
|
-
localPath: string;
|
|
48
|
-
title?: string;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface OutboundEnvelope {
|
|
52
|
-
platform: Platform;
|
|
53
|
-
accountId: string;
|
|
54
|
-
chatId: string;
|
|
55
|
-
threadId?: string;
|
|
56
|
-
replyToMessageId?: string;
|
|
57
|
-
mode: "create" | "update";
|
|
58
|
-
targetMessageId?: string;
|
|
59
|
-
text: string;
|
|
60
|
-
attachments?: OutboundAttachment[];
|
|
61
|
-
metadata?: Record<string, string>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface ConnectorSendResult {
|
|
65
|
-
messageId?: string;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface ConnectorTypingEnvelope {
|
|
69
|
-
platform: Platform;
|
|
70
|
-
accountId: string;
|
|
71
|
-
chatId: string;
|
|
72
|
-
threadId?: string;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface ConnectorContext {
|
|
76
|
-
emitInbound: (msg: InboundEnvelope) => Promise<void>;
|
|
77
|
-
emitControl: (event: {
|
|
78
|
-
type: "stop";
|
|
79
|
-
connectorId: string;
|
|
80
|
-
platform: Platform;
|
|
81
|
-
accountId: string;
|
|
82
|
-
chatId: string;
|
|
83
|
-
threadId?: string;
|
|
84
|
-
}) => Promise<void>;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export type ConnectorUpdateStrategy = "edit" | "final_only" | "append";
|
|
88
|
-
|
|
89
|
-
export interface ConnectorCapabilities {
|
|
90
|
-
updateStrategy: ConnectorUpdateStrategy;
|
|
91
|
-
supportedSources: BindingSourceType[];
|
|
92
|
-
supportsThread: boolean;
|
|
93
|
-
supportsTyping: boolean;
|
|
94
|
-
supportsFileUpload: boolean;
|
|
95
|
-
maxTextLength?: number;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export interface ConnectorPlugin {
|
|
99
|
-
readonly id: string;
|
|
100
|
-
readonly platform: Platform;
|
|
101
|
-
readonly name: string;
|
|
102
|
-
readonly capabilities: ConnectorCapabilities;
|
|
103
|
-
start(ctx: ConnectorContext): Promise<void>;
|
|
104
|
-
send(message: OutboundEnvelope): Promise<ConnectorSendResult>;
|
|
105
|
-
sendTyping?(message: ConnectorTypingEnvelope): Promise<void>;
|
|
106
|
-
stop(): Promise<void>;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface RouteDefaultsConfig {
|
|
110
|
-
provider: string;
|
|
111
|
-
sandbox: string;
|
|
112
|
-
tools: ToolProfile;
|
|
113
|
-
mentions: MentionPolicy;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export interface RouteProfile {
|
|
117
|
-
projectRoot: string;
|
|
118
|
-
tools: ToolProfile;
|
|
119
|
-
mentions: MentionPolicy;
|
|
120
|
-
provider: string;
|
|
121
|
-
sandbox: string;
|
|
122
|
-
systemPromptFile?: string;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export interface RoutesConfig {
|
|
126
|
-
defaults: RouteDefaultsConfig;
|
|
127
|
-
items: Record<string, RouteProfile>;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export interface ExtensionPackageConfig {
|
|
131
|
-
package: string;
|
|
132
|
-
enabled?: boolean;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export interface ExtensionsConfig {
|
|
136
|
-
allowList: ExtensionPackageConfig[];
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export interface ExtensionInstanceConfig {
|
|
140
|
-
type: string;
|
|
141
|
-
config: Record<string, unknown>;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export interface ProvidersConfig {
|
|
145
|
-
default: string;
|
|
146
|
-
items: Record<string, ExtensionInstanceConfig>;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export interface ConnectorsConfig {
|
|
150
|
-
items: Record<string, ExtensionInstanceConfig>;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export interface SandboxesConfig {
|
|
154
|
-
default?: string;
|
|
155
|
-
items: Record<string, ExtensionInstanceConfig>;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export interface BindingConfig {
|
|
159
|
-
connector: string;
|
|
160
|
-
source: BindingSource;
|
|
161
|
-
route: string;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export interface BindingsConfig {
|
|
165
|
-
items: Record<string, BindingConfig>;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export interface DataConfig {
|
|
169
|
-
rootDir: string;
|
|
170
|
-
sessionsDir: string;
|
|
171
|
-
attachmentsDir: string;
|
|
172
|
-
logsDir: string;
|
|
173
|
-
stateDir: string;
|
|
174
|
-
dedupTtlMs: number;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export interface GatewayConfig {
|
|
178
|
-
extensions: ExtensionsConfig;
|
|
179
|
-
providers: ProvidersConfig;
|
|
180
|
-
connectors: ConnectorsConfig;
|
|
181
|
-
sandboxes: SandboxesConfig;
|
|
182
|
-
routes: RoutesConfig;
|
|
183
|
-
bindings: BindingsConfig;
|
|
184
|
-
data: DataConfig;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export interface RouteResolution {
|
|
188
|
-
routeId: string;
|
|
189
|
-
profile: RouteProfile;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export interface BindingResolution {
|
|
193
|
-
bindingId: string;
|
|
194
|
-
config: BindingConfig;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export interface PromptPayload {
|
|
198
|
-
text: string;
|
|
199
|
-
images: ImageContent[];
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export type GatewayAgentEvent =
|
|
203
|
-
| { type: "message_delta"; delta: string }
|
|
204
|
-
| { type: "message_complete"; text: string }
|
|
205
|
-
| { type: "tool_start"; toolName: string }
|
|
206
|
-
| { type: "tool_end"; toolName: string; isError: boolean; output: string }
|
|
207
|
-
| { type: "status"; message: string };
|
|
208
|
-
|
|
209
|
-
export interface GatewayAgentRuntime {
|
|
210
|
-
prompt(text: string, options?: { images?: ImageContent[] }): Promise<void>;
|
|
211
|
-
subscribe(listener: (event: GatewayAgentEvent) => void): () => void;
|
|
212
|
-
abort(): Promise<void>;
|
|
213
|
-
dispose(): void;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export interface ConversationRuntime {
|
|
217
|
-
key: string;
|
|
218
|
-
routeId: string;
|
|
219
|
-
route: RouteProfile;
|
|
220
|
-
providerId: string;
|
|
221
|
-
sandboxId: string;
|
|
222
|
-
runtime: GatewayAgentRuntime;
|
|
223
|
-
close: () => Promise<void>;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
export interface ExtensionContributionManifest {
|
|
227
|
-
id: string;
|
|
228
|
-
kind: ExtensionKind;
|
|
229
|
-
entry: string;
|
|
230
|
-
capabilities?: Record<string, unknown>;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export interface ExtensionManifest {
|
|
234
|
-
apiVersion: ExtensionApiVersion | string;
|
|
235
|
-
name: string;
|
|
236
|
-
version: string;
|
|
237
|
-
contributions: ExtensionContributionManifest[];
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export interface ExtensionHostContext {
|
|
241
|
-
logger: GatewayLogger;
|
|
242
|
-
configBaseDir: string;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
export interface ProviderRuntimeCreateOptions {
|
|
246
|
-
conversationKey: string;
|
|
247
|
-
route: RouteResolution;
|
|
248
|
-
inbound: InboundEnvelope;
|
|
249
|
-
executor: Executor;
|
|
250
|
-
sessionPolicy?: "shared-session" | "ephemeral";
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export interface ProviderSessionArchiveOptions {
|
|
254
|
-
conversationKey: string;
|
|
255
|
-
inbound: InboundEnvelope;
|
|
256
|
-
sessionPolicy?: "shared-session" | "ephemeral";
|
|
257
|
-
archivedAtMs?: number;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
export interface ProviderSessionArchiveResult {
|
|
261
|
-
archived: boolean;
|
|
262
|
-
archivePath?: string;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
export interface ProviderInstance {
|
|
266
|
-
id: string;
|
|
267
|
-
createRuntime(options: ProviderRuntimeCreateOptions): Promise<GatewayAgentRuntime>;
|
|
268
|
-
archiveSession?(options: ProviderSessionArchiveOptions): Promise<ProviderSessionArchiveResult>;
|
|
269
|
-
close?: () => Promise<void>;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export interface ProviderInstanceCreateOptions {
|
|
273
|
-
instanceId: string;
|
|
274
|
-
config: Record<string, unknown>;
|
|
275
|
-
host: ExtensionHostContext;
|
|
276
|
-
data: DataConfig;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
export interface ProviderContributionModule {
|
|
280
|
-
kind: "provider";
|
|
281
|
-
configSchema?: Record<string, unknown>;
|
|
282
|
-
createInstance(options: ProviderInstanceCreateOptions): Promise<ProviderInstance> | ProviderInstance;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
export interface ConnectorInstanceCreateOptions {
|
|
286
|
-
instanceId: string;
|
|
287
|
-
config: Record<string, unknown>;
|
|
288
|
-
host: ExtensionHostContext;
|
|
289
|
-
attachmentsRoot: string;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
export interface ConnectorContributionModule {
|
|
293
|
-
kind: "connector";
|
|
294
|
-
configSchema?: Record<string, unknown>;
|
|
295
|
-
createInstance(options: ConnectorInstanceCreateOptions): Promise<ConnectorPlugin> | ConnectorPlugin;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
export interface SandboxInstance {
|
|
299
|
-
id: string;
|
|
300
|
-
executor: Executor;
|
|
301
|
-
close?: () => Promise<void>;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
export interface SandboxInstanceCreateOptions {
|
|
305
|
-
instanceId: string;
|
|
306
|
-
config: Record<string, unknown>;
|
|
307
|
-
host: ExtensionHostContext;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export interface SandboxContributionModule {
|
|
311
|
-
kind: "sandbox";
|
|
312
|
-
configSchema?: Record<string, unknown>;
|
|
313
|
-
createInstance(options: SandboxInstanceCreateOptions): Promise<SandboxInstance> | SandboxInstance;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
export type ExtensionContributionModule = ProviderContributionModule | ConnectorContributionModule | SandboxContributionModule;
|
|
317
|
-
|
|
318
|
-
export type GatewayLogger = Logger;
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ConnectorPlugin,
|
|
3
|
-
GatewayLogger,
|
|
4
|
-
InboundEnvelope,
|
|
5
|
-
} from "./types.js";
|
|
6
|
-
|
|
7
|
-
const DEFAULT_TYPING_INITIAL_DELAY_MS = 0;
|
|
8
|
-
const DEFAULT_TYPING_KEEPALIVE_INTERVAL_MS = 8_000;
|
|
9
|
-
|
|
10
|
-
export interface TypingController {
|
|
11
|
-
prime: () => Promise<void>;
|
|
12
|
-
markVisibleOutput: () => void;
|
|
13
|
-
stop: () => void;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function createTypingKeepAliveController(
|
|
17
|
-
connector: ConnectorPlugin,
|
|
18
|
-
message: InboundEnvelope,
|
|
19
|
-
logger: GatewayLogger,
|
|
20
|
-
options: {
|
|
21
|
-
initialDelayMs?: number;
|
|
22
|
-
keepaliveIntervalMs?: number;
|
|
23
|
-
} = {},
|
|
24
|
-
): TypingController {
|
|
25
|
-
const sendTypingMethod = connector.sendTyping;
|
|
26
|
-
if (!connector.capabilities.supportsTyping || !sendTypingMethod) {
|
|
27
|
-
return {
|
|
28
|
-
prime: async () => {},
|
|
29
|
-
markVisibleOutput: () => {},
|
|
30
|
-
stop: () => {},
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const typingTarget = {
|
|
35
|
-
platform: message.platform,
|
|
36
|
-
accountId: message.accountId,
|
|
37
|
-
chatId: message.chatId,
|
|
38
|
-
...(message.threadId ? { threadId: message.threadId } : {}),
|
|
39
|
-
};
|
|
40
|
-
const initialDelayMs = options.initialDelayMs ?? DEFAULT_TYPING_INITIAL_DELAY_MS;
|
|
41
|
-
const keepaliveIntervalMs = options.keepaliveIntervalMs ?? DEFAULT_TYPING_KEEPALIVE_INTERVAL_MS;
|
|
42
|
-
let stopped = false;
|
|
43
|
-
let visibleOutputSent = false;
|
|
44
|
-
let inFlight = false;
|
|
45
|
-
let keepaliveTimer: NodeJS.Timeout | null = null;
|
|
46
|
-
|
|
47
|
-
const clearKeepalive = (): void => {
|
|
48
|
-
if (!keepaliveTimer) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
clearInterval(keepaliveTimer);
|
|
52
|
-
keepaliveTimer = null;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const sendTyping = async (): Promise<void> => {
|
|
56
|
-
if (stopped || visibleOutputSent || inFlight) {
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
inFlight = true;
|
|
61
|
-
try {
|
|
62
|
-
await sendTypingMethod.call(connector, typingTarget);
|
|
63
|
-
} catch (error) {
|
|
64
|
-
logger.warn(
|
|
65
|
-
{
|
|
66
|
-
err: error,
|
|
67
|
-
connectorId: message.connectorId,
|
|
68
|
-
chatId: message.chatId,
|
|
69
|
-
threadId: message.threadId,
|
|
70
|
-
},
|
|
71
|
-
"Failed to send typing indicator",
|
|
72
|
-
);
|
|
73
|
-
} finally {
|
|
74
|
-
inFlight = false;
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const startKeepalive = (): void => {
|
|
79
|
-
if (keepaliveTimer || stopped || visibleOutputSent) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
keepaliveTimer = setInterval(() => {
|
|
84
|
-
void sendTyping();
|
|
85
|
-
}, keepaliveIntervalMs);
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
prime: async () => {
|
|
90
|
-
if (stopped || visibleOutputSent) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (initialDelayMs > 0) {
|
|
95
|
-
await new Promise<void>((resolve) => {
|
|
96
|
-
const timer = setTimeout(resolve, initialDelayMs);
|
|
97
|
-
if (stopped || visibleOutputSent) {
|
|
98
|
-
clearTimeout(timer);
|
|
99
|
-
resolve();
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
await sendTyping();
|
|
105
|
-
startKeepalive();
|
|
106
|
-
},
|
|
107
|
-
markVisibleOutput: () => {
|
|
108
|
-
if (visibleOutputSent) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
visibleOutputSent = true;
|
|
112
|
-
clearKeepalive();
|
|
113
|
-
},
|
|
114
|
-
stop: () => {
|
|
115
|
-
stopped = true;
|
|
116
|
-
clearKeepalive();
|
|
117
|
-
},
|
|
118
|
-
};
|
|
119
|
-
}
|
package/src/cron/config.ts
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { dirname, isAbsolute, resolve } from "node:path";
|
|
2
|
-
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
import type { GatewayConfig } from "../core/types.js";
|
|
6
|
-
import type { CronConfig } from "./types.js";
|
|
7
|
-
|
|
8
|
-
interface LoadCronConfigOptions {
|
|
9
|
-
gatewayConfigPath: string;
|
|
10
|
-
gatewayConfig: GatewayConfig;
|
|
11
|
-
explicitCronConfigPath?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface CronConfigResolution {
|
|
15
|
-
configPath: string;
|
|
16
|
-
source: "explicit" | "env" | "gateway" | "state";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface LoadedCronConfig {
|
|
20
|
-
configPath: string;
|
|
21
|
-
source: "explicit" | "env" | "gateway" | "state";
|
|
22
|
-
config: CronConfig;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const rawCronConfigSchema = z.object({
|
|
26
|
-
enabled: z.boolean().default(true),
|
|
27
|
-
storeFile: z.string().min(1).optional(),
|
|
28
|
-
runLogFile: z.string().min(1).optional(),
|
|
29
|
-
pollIntervalMs: z.number().int().positive().default(10_000),
|
|
30
|
-
maxConcurrentRuns: z.number().int().positive().default(1),
|
|
31
|
-
runMissedOnStartup: z.boolean().default(true),
|
|
32
|
-
jobTimeoutMs: z.number().int().positive().default(10 * 60 * 1000),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
type RawCronConfig = z.infer<typeof rawCronConfigSchema>;
|
|
36
|
-
|
|
37
|
-
function expandHome(value: string): string {
|
|
38
|
-
if (value === "~") {
|
|
39
|
-
return homedir();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
43
|
-
return resolve(homedir(), value.slice(2));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return value;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function gatewayConfigBaseDir(gatewayConfigPath: string): string {
|
|
50
|
-
const configDir = dirname(resolve(gatewayConfigPath));
|
|
51
|
-
return configDir.endsWith("/config") || configDir.endsWith("\\config")
|
|
52
|
-
? resolve(configDir, "..")
|
|
53
|
-
: configDir;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function resolvePathFromBase(baseDir: string, value: string): string {
|
|
57
|
-
const expanded = expandHome(value);
|
|
58
|
-
return isAbsolute(expanded) ? resolve(expanded) : resolve(baseDir, expanded);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async function fileExists(filePath: string): Promise<boolean> {
|
|
62
|
-
try {
|
|
63
|
-
await access(filePath);
|
|
64
|
-
return true;
|
|
65
|
-
} catch {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function defaultCronConfigPayload(): RawCronConfig {
|
|
71
|
-
return {
|
|
72
|
-
enabled: true,
|
|
73
|
-
storeFile: "./data/state/cron-jobs.json",
|
|
74
|
-
runLogFile: "./data/state/cron-runs.jsonl",
|
|
75
|
-
pollIntervalMs: 10_000,
|
|
76
|
-
maxConcurrentRuns: 1,
|
|
77
|
-
runMissedOnStartup: true,
|
|
78
|
-
jobTimeoutMs: 10 * 60 * 1000,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async function ensureCronConfigFile(configPath: string): Promise<void> {
|
|
83
|
-
if (await fileExists(configPath)) {
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
await mkdir(dirname(configPath), { recursive: true });
|
|
88
|
-
const payload = `${JSON.stringify(defaultCronConfigPayload(), null, 2)}\n`;
|
|
89
|
-
await writeFile(configPath, payload, "utf-8");
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function resolveCronConfigPath(options: LoadCronConfigOptions): CronConfigResolution {
|
|
93
|
-
if (options.explicitCronConfigPath && options.explicitCronConfigPath.trim().length > 0) {
|
|
94
|
-
const rawPath = options.explicitCronConfigPath.trim();
|
|
95
|
-
const expanded = expandHome(rawPath);
|
|
96
|
-
const configPath = isAbsolute(expanded) ? resolve(expanded) : resolve(process.cwd(), expanded);
|
|
97
|
-
return { configPath, source: "explicit" };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const envPath = process.env.DOBBY_CRON_CONFIG_PATH?.trim();
|
|
101
|
-
if (envPath) {
|
|
102
|
-
const expanded = expandHome(envPath);
|
|
103
|
-
const configPath = isAbsolute(expanded) ? resolve(expanded) : resolve(process.cwd(), expanded);
|
|
104
|
-
return { configPath, source: "env" };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const candidate = resolve(dirname(resolve(options.gatewayConfigPath)), "cron.json");
|
|
108
|
-
if (process.env.DOBBY_CRON_CONFIG_PATH === undefined && options.explicitCronConfigPath === undefined) {
|
|
109
|
-
// no-op branch to make intent explicit for the resolution order
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return {
|
|
113
|
-
configPath: candidate,
|
|
114
|
-
source: "gateway",
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function normalizeCronConfig(gatewayConfigPath: string, gatewayConfig: GatewayConfig, raw: RawCronConfig): CronConfig {
|
|
119
|
-
const baseDir = gatewayConfigBaseDir(gatewayConfigPath);
|
|
120
|
-
const defaultStoreFile = resolve(gatewayConfig.data.stateDir, "cron-jobs.json");
|
|
121
|
-
const defaultRunLogFile = resolve(gatewayConfig.data.stateDir, "cron-runs.jsonl");
|
|
122
|
-
return {
|
|
123
|
-
enabled: raw.enabled,
|
|
124
|
-
storeFile: raw.storeFile ? resolvePathFromBase(baseDir, raw.storeFile) : defaultStoreFile,
|
|
125
|
-
runLogFile: raw.runLogFile ? resolvePathFromBase(baseDir, raw.runLogFile) : defaultRunLogFile,
|
|
126
|
-
pollIntervalMs: raw.pollIntervalMs,
|
|
127
|
-
maxConcurrentRuns: raw.maxConcurrentRuns,
|
|
128
|
-
runMissedOnStartup: raw.runMissedOnStartup,
|
|
129
|
-
jobTimeoutMs: raw.jobTimeoutMs,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export async function loadCronConfig(options: LoadCronConfigOptions): Promise<LoadedCronConfig> {
|
|
134
|
-
const resolved = resolveCronConfigPath(options);
|
|
135
|
-
const gatewayFallbackPath = resolve(options.gatewayConfig.data.stateDir, "cron.config.json");
|
|
136
|
-
|
|
137
|
-
let configPath = resolved.configPath;
|
|
138
|
-
let source = resolved.source;
|
|
139
|
-
|
|
140
|
-
if (source === "gateway" && !(await fileExists(configPath))) {
|
|
141
|
-
configPath = gatewayFallbackPath;
|
|
142
|
-
source = "state";
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
await ensureCronConfigFile(configPath);
|
|
146
|
-
const raw = await readFile(configPath, "utf-8");
|
|
147
|
-
const parsed = rawCronConfigSchema.parse(JSON.parse(raw));
|
|
148
|
-
|
|
149
|
-
return {
|
|
150
|
-
configPath,
|
|
151
|
-
source,
|
|
152
|
-
config: normalizeCronConfig(options.gatewayConfigPath, options.gatewayConfig, parsed),
|
|
153
|
-
};
|
|
154
|
-
}
|