@zhanguym/chatroom 1.0.0 → 1.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/application.d.ts +0 -1
- package/dist/app/application.js +8 -7
- package/dist/app/event-bus.d.ts +13 -10
- package/dist/app/git-access.d.ts +50 -0
- package/dist/app/git-access.js +2 -0
- package/dist/app/service-registry.d.ts +11 -0
- package/dist/app/service-registry.js +17 -0
- package/dist/app/workspace-access.d.ts +24 -0
- package/dist/app/workspace-access.js +2 -0
- package/dist/auth/ingress-policy.d.ts +2 -0
- package/dist/auth/ingress-policy.js +14 -2
- package/dist/auth/passkey-service.js +1 -1
- package/dist/cli/run-cli.js +1 -1
- package/dist/core/fs/safe-directory.d.ts +9 -0
- package/dist/core/fs/safe-directory.js +129 -0
- package/dist/core/operations/repository.d.ts +2 -0
- package/dist/core/runtime/line-process.d.ts +19 -0
- package/dist/core/runtime/line-process.js +51 -0
- package/dist/infrastructure/database/operation-repository.js +8 -2
- package/dist/infrastructure/database/schema.d.ts +1 -1
- package/dist/infrastructure/database/schema.js +62 -0
- package/dist/infrastructure/http/http-server.js +1 -1
- package/dist/native/linux/chatroom-computer-helper +0 -0
- package/dist/native/macos/ChatRoomComputerHelper.app/Contents/MacOS/chatroom-computer-helper +0 -0
- package/dist/native/windows/chatroom-computer-helper.exe +0 -0
- package/dist/operations/operation-log.js +16 -4
- package/dist/plugins/agent/async-queue.d.ts +10 -0
- package/dist/plugins/agent/async-queue.js +49 -0
- package/dist/plugins/agent/mcp.d.ts +3 -0
- package/dist/plugins/agent/mcp.js +502 -0
- package/dist/plugins/agent/plugin.d.ts +4 -0
- package/dist/plugins/agent/plugin.js +35 -0
- package/dist/plugins/agent/provider.d.ts +132 -0
- package/dist/plugins/agent/providers/codex/mapping.d.ts +56 -0
- package/dist/plugins/agent/providers/codex/mapping.js +427 -0
- package/dist/plugins/agent/providers/codex/provider.d.ts +84 -0
- package/dist/plugins/agent/providers/codex/provider.js +828 -0
- package/dist/plugins/agent/providers/codex/rpc.d.ts +40 -0
- package/dist/plugins/agent/providers/codex/rpc.js +227 -0
- package/dist/plugins/agent/providers/common.d.ts +11 -0
- package/dist/plugins/agent/providers/common.js +75 -0
- package/dist/plugins/agent/providers/index.d.ts +3 -0
- package/dist/plugins/agent/providers/index.js +4 -0
- package/dist/plugins/agent/repository.d.ts +21 -0
- package/dist/plugins/agent/repository.js +226 -0
- package/dist/plugins/agent/runtime-config.d.ts +5 -0
- package/dist/plugins/agent/runtime-config.js +60 -0
- package/dist/plugins/agent/runtime-files.d.ts +8 -0
- package/dist/plugins/agent/runtime-files.js +170 -0
- package/dist/plugins/agent/runtime-state.d.ts +17 -0
- package/dist/plugins/agent/runtime-state.js +133 -0
- package/dist/plugins/agent/runtime.d.ts +60 -0
- package/dist/plugins/agent/runtime.js +928 -0
- package/dist/plugins/agent/store.d.ts +17 -0
- package/dist/plugins/agent/store.js +1 -0
- package/dist/plugins/agent/types.d.ts +320 -0
- package/dist/plugins/agent/types.js +13 -0
- package/dist/plugins/cloud/plugin.d.ts +1 -1
- package/dist/plugins/cloud/plugin.js +3 -3
- package/dist/plugins/cloud/tunnel-client.js +6 -7
- package/dist/plugins/computer/computer-schemas.d.ts +7 -7
- package/dist/plugins/computer/computer-service.d.ts +3 -0
- package/dist/plugins/computer/computer-service.js +33 -1
- package/dist/plugins/computer/plugin.d.ts +1 -1
- package/dist/plugins/computer/plugin.js +1 -1
- package/dist/plugins/git/git-service.d.ts +3 -2
- package/dist/plugins/git/git-service.js +37 -1
- package/dist/plugins/git/plugin.d.ts +0 -2
- package/dist/plugins/git/plugin.js +3 -3
- package/dist/plugins/process/plugin.d.ts +1 -1
- package/dist/plugins/process/plugin.js +3 -3
- package/dist/plugins/process/process-supervisor.d.ts +1 -0
- package/dist/plugins/process/process-supervisor.js +15 -4
- package/dist/plugins/types.d.ts +1 -11
- package/dist/plugins/types.js +1 -17
- package/dist/plugins/web/api-types.d.ts +20 -5
- package/dist/plugins/web/http/agent-api-router.d.ts +3 -0
- package/dist/plugins/web/http/agent-api-router.js +254 -0
- package/dist/plugins/web/http/api-router.js +9 -0
- package/dist/plugins/web/http/computer-api-router.js +21 -6
- package/dist/plugins/web/http/process-api-router.js +3 -0
- package/dist/plugins/web/http/workspace-api-router.js +79 -6
- package/dist/plugins/web/plugin.d.ts +1 -1
- package/dist/plugins/web/plugin.js +5 -4
- package/dist/plugins/web/runtime.d.ts +6 -3
- package/dist/plugins/web/runtime.js +6 -1
- package/dist/plugins/workspace/mcp.js +16 -0
- package/dist/plugins/workspace/metadata.d.ts +1 -1
- package/dist/plugins/workspace/plugin.d.ts +1 -1
- package/dist/plugins/workspace/plugin.js +5 -2
- package/dist/plugins/workspace/types.d.ts +1 -18
- package/dist/plugins/workspace/workspace-fs.d.ts +9 -3
- package/dist/plugins/workspace/workspace-fs.js +78 -125
- package/dist/plugins/workspace/workspace-root-policy.d.ts +9 -0
- package/dist/plugins/workspace/workspace-root-policy.js +56 -0
- package/dist/plugins/workspace/workspace-service.d.ts +11 -6
- package/dist/plugins/workspace/workspace-service.js +39 -49
- package/dist/web/assets/AgentView-DKuspiki.js +4 -0
- package/dist/web/assets/AgentView-DYJeMJLX.css +1 -0
- package/dist/web/assets/{CloudView-CHjVbp-5.css → CloudView-DVVvwuWW.css} +1 -1
- package/dist/web/assets/CloudView-PbREbJgz.js +1 -0
- package/dist/web/assets/CodeViewer.vue_vue_type_script_setup_true_lang-CiFNEpWo.js +3 -0
- package/dist/web/assets/ComputerView-BM0u3wSF.css +1 -0
- package/dist/web/assets/ComputerView-BRb2sE0Z.js +1 -0
- package/dist/web/assets/McpToolsView-B8NSFdf4.js +1 -0
- package/dist/web/assets/McpToolsView-C22ZbSuV.css +1 -0
- package/dist/web/assets/OperationsView-BjTY2lIh.css +1 -0
- package/dist/web/assets/OperationsView-Cavi-6SZ.js +4 -0
- package/dist/web/assets/ProcessesView-Ce6iVwjA.css +1 -0
- package/dist/web/assets/ProcessesView-UO48Nh2q.js +4 -0
- package/dist/web/assets/StateChip.vue_vue_type_script_setup_true_lang-Bvc9wRyA.js +1 -0
- package/dist/web/assets/SystemLogsView-BXmOrmu5.js +1 -0
- package/dist/web/assets/SystemLogsView-CofP4Jvi.css +1 -0
- package/dist/web/assets/VSelect-BPRXx8KM.js +1 -0
- package/dist/web/assets/VSpacer-Cl-QiwaM.js +1 -0
- package/dist/web/assets/VSwitch-C0XNj1lR.js +1 -0
- package/dist/web/assets/{VTabs-qBcuuXh3.js → VTabs-CHj39Ket.js} +1 -1
- package/dist/web/assets/VTextarea-BIcUWOU6.js +16 -0
- package/dist/web/assets/VTextarea-DG1zE1as.css +1 -0
- package/dist/web/assets/WorkspacesView-DPCt6kYy.css +1 -0
- package/dist/web/assets/WorkspacesView-rY6RXeiR.js +2 -0
- package/dist/web/assets/entity-refresh-queue-wQii8Dl5.js +1 -0
- package/dist/web/assets/{index-CkjqXRSj.css → index-BPpl3-sP.css} +1 -1
- package/dist/web/assets/index-Dt-pWiW1.js +19 -0
- package/dist/web/assets/{syntax-highlight-B5ArnyrC.js → syntax-highlight-C_fuMcwC.js} +1 -1
- package/dist/web/assets/useMasterDetailFocus-D0j-KcXv.js +1 -0
- package/dist/web/assets/useOperationLabels-DR8r6Vrl.js +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +4 -2
- package/dist/plugins/git/types.d.ts +0 -32
- package/dist/web/assets/CloudView-CvX0dkgu.js +0 -1
- package/dist/web/assets/CodeViewer.vue_vue_type_script_setup_true_lang-B5TxGkUW.js +0 -3
- package/dist/web/assets/ComputerView-91Z9Cefw.css +0 -1
- package/dist/web/assets/ComputerView-OOyEqWml.js +0 -1
- package/dist/web/assets/McpToolsView-BTnolyS6.css +0 -1
- package/dist/web/assets/McpToolsView-DjXWTKrZ.js +0 -1
- package/dist/web/assets/OperationsView-DqTY51Cr.js +0 -4
- package/dist/web/assets/ProcessesView-C13BykIa.js +0 -4
- package/dist/web/assets/StateChip.vue_vue_type_script_setup_true_lang-DyOhJmR6.js +0 -1
- package/dist/web/assets/SystemLogsView-Ci0u4BTb.js +0 -1
- package/dist/web/assets/VSelect-DrRpKyYI.js +0 -1
- package/dist/web/assets/VSpacer-C3wAY3F0.js +0 -1
- package/dist/web/assets/VSwitch-CxusR4iO.js +0 -1
- package/dist/web/assets/WorkspacesView-BzQ0aH74.css +0 -1
- package/dist/web/assets/WorkspacesView-CijIvfsp.js +0 -2
- package/dist/web/assets/index-BegKQ3Yd.js +0 -19
- package/dist/web/assets/useOperationLabels-BDjzGDkT.js +0 -1
- /package/dist/{plugins/process → core/runtime}/head-tail-buffer.d.ts +0 -0
- /package/dist/{plugins/process → core/runtime}/head-tail-buffer.js +0 -0
- /package/dist/plugins/{git/types.js → agent/provider.js} +0 -0
|
@@ -31,7 +31,11 @@ export class OperationLog {
|
|
|
31
31
|
durationMs: null,
|
|
32
32
|
};
|
|
33
33
|
this.repository.insert(operation);
|
|
34
|
-
this.eventBus.emit({
|
|
34
|
+
this.eventBus.emit({
|
|
35
|
+
type: "operation",
|
|
36
|
+
operationId: operation.operationId,
|
|
37
|
+
pluginId: operation.pluginId,
|
|
38
|
+
});
|
|
35
39
|
return operation;
|
|
36
40
|
}
|
|
37
41
|
finish(operationId, status, output, error) {
|
|
@@ -47,7 +51,11 @@ export class OperationLog {
|
|
|
47
51
|
operation.finishedAt = finishedAt.toISOString();
|
|
48
52
|
operation.durationMs = Math.max(0, finishedAt.getTime() - new Date(operation.startedAt).getTime());
|
|
49
53
|
this.repository.update(operation);
|
|
50
|
-
this.eventBus.emit({
|
|
54
|
+
this.eventBus.emit({
|
|
55
|
+
type: "operation",
|
|
56
|
+
operationId: operation.operationId,
|
|
57
|
+
pluginId: operation.pluginId,
|
|
58
|
+
});
|
|
51
59
|
return operation;
|
|
52
60
|
}
|
|
53
61
|
async run(request, action) {
|
|
@@ -78,12 +86,16 @@ export class OperationLog {
|
|
|
78
86
|
if (references.processId !== undefined)
|
|
79
87
|
operation.processId = references.processId;
|
|
80
88
|
this.repository.update(operation);
|
|
81
|
-
this.eventBus.emit({
|
|
89
|
+
this.eventBus.emit({
|
|
90
|
+
type: "operation",
|
|
91
|
+
operationId: operation.operationId,
|
|
92
|
+
pluginId: operation.pluginId,
|
|
93
|
+
});
|
|
82
94
|
return operation;
|
|
83
95
|
}
|
|
84
96
|
clearHistory() {
|
|
85
97
|
const result = this.repository.clearHistory();
|
|
86
|
-
this.eventBus.emit({ type: "operations-cleared"
|
|
98
|
+
this.eventBus.emit({ type: "operations-cleared" });
|
|
87
99
|
return result;
|
|
88
100
|
}
|
|
89
101
|
reconcileInterrupted() {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class AsyncQueue<T> implements AsyncIterable<T> {
|
|
2
|
+
private readonly values;
|
|
3
|
+
private readonly readers;
|
|
4
|
+
private ended;
|
|
5
|
+
private failure;
|
|
6
|
+
push(value: T): void;
|
|
7
|
+
close(): void;
|
|
8
|
+
fail(error: unknown): void;
|
|
9
|
+
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export class AsyncQueue {
|
|
2
|
+
values = [];
|
|
3
|
+
readers = [];
|
|
4
|
+
ended = false;
|
|
5
|
+
failure = null;
|
|
6
|
+
push(value) {
|
|
7
|
+
if (this.ended)
|
|
8
|
+
throw new Error("Queue is closed");
|
|
9
|
+
const reader = this.readers.shift();
|
|
10
|
+
if (reader)
|
|
11
|
+
reader.resolve({ value, done: false });
|
|
12
|
+
else
|
|
13
|
+
this.values.push(value);
|
|
14
|
+
}
|
|
15
|
+
close() {
|
|
16
|
+
if (this.ended)
|
|
17
|
+
return;
|
|
18
|
+
this.ended = true;
|
|
19
|
+
for (const reader of this.readers.splice(0))
|
|
20
|
+
reader.resolve({ value: undefined, done: true });
|
|
21
|
+
}
|
|
22
|
+
fail(error) {
|
|
23
|
+
if (this.ended)
|
|
24
|
+
return;
|
|
25
|
+
this.failure = error;
|
|
26
|
+
this.ended = true;
|
|
27
|
+
for (const reader of this.readers.splice(0))
|
|
28
|
+
reader.reject(error);
|
|
29
|
+
}
|
|
30
|
+
[Symbol.asyncIterator]() {
|
|
31
|
+
return {
|
|
32
|
+
next: () => {
|
|
33
|
+
const value = this.values.shift();
|
|
34
|
+
if (value !== undefined)
|
|
35
|
+
return Promise.resolve({ value, done: false });
|
|
36
|
+
if (this.failure)
|
|
37
|
+
return Promise.reject(this.failure);
|
|
38
|
+
if (this.ended)
|
|
39
|
+
return Promise.resolve({
|
|
40
|
+
value: undefined,
|
|
41
|
+
done: true,
|
|
42
|
+
});
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
this.readers.push({ resolve, reject });
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { closedRead, destructiveLocalMutation, openWorldMutation, } from "#mcp/server/tool-support";
|
|
3
|
+
import { AGENT_PROVIDER_ID_PATTERN, AGENT_PERMISSION_MODES, } from "./types.js";
|
|
4
|
+
const provider = z
|
|
5
|
+
.string()
|
|
6
|
+
.regex(AGENT_PROVIDER_ID_PATTERN)
|
|
7
|
+
.describe("Registered Agent provider identifier.");
|
|
8
|
+
const attachment = z.object({
|
|
9
|
+
kind: z.enum(["image", "audio", "skill", "file"]),
|
|
10
|
+
name: z.string(),
|
|
11
|
+
path: z.string(),
|
|
12
|
+
mimeType: z.string().nullable().default(null),
|
|
13
|
+
});
|
|
14
|
+
const granularApprovalPolicy = z.object({
|
|
15
|
+
granular: z.object({
|
|
16
|
+
sandbox_approval: z.boolean(),
|
|
17
|
+
rules: z.boolean(),
|
|
18
|
+
skill_approval: z.boolean(),
|
|
19
|
+
request_permissions: z.boolean(),
|
|
20
|
+
mcp_elicitations: z.boolean(),
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
const approvalPolicy = z
|
|
24
|
+
.union([z.enum(["untrusted", "on-request", "never"]), granularApprovalPolicy])
|
|
25
|
+
.nullable()
|
|
26
|
+
.describe('Codex approvalPolicy: "untrusted", "on-request", {granular:{...}}, "never", or null for the provider default.');
|
|
27
|
+
const approvalsReviewer = z
|
|
28
|
+
.enum(["user", "auto_review", "guardian_subagent"])
|
|
29
|
+
.nullable()
|
|
30
|
+
.describe('Codex approvalsReviewer: "user", "auto_review", "guardian_subagent", or null for the provider default.');
|
|
31
|
+
const permissionMode = z
|
|
32
|
+
.enum(AGENT_PERMISSION_MODES)
|
|
33
|
+
.nullable()
|
|
34
|
+
.describe("Provider-native permissions. Codex supports read-only, workspace-write, and danger-full-access. Null uses the provider default. Read agent_providers for supported options.");
|
|
35
|
+
const settings = {
|
|
36
|
+
model: z
|
|
37
|
+
.string()
|
|
38
|
+
.min(1)
|
|
39
|
+
.nullable()
|
|
40
|
+
.describe("Model identifier advertised by agent_models; null selects the provider default."),
|
|
41
|
+
reasoningEffort: z
|
|
42
|
+
.string()
|
|
43
|
+
.min(1)
|
|
44
|
+
.nullable()
|
|
45
|
+
.describe("A reasoning effort advertised by the selected model; null uses its default."),
|
|
46
|
+
reasoningSummary: z
|
|
47
|
+
.enum(["auto", "concise", "detailed", "none"])
|
|
48
|
+
.nullable()
|
|
49
|
+
.describe("A reasoning summary value supported by the provider/model; null uses its default."),
|
|
50
|
+
serviceTier: z
|
|
51
|
+
.string()
|
|
52
|
+
.min(1)
|
|
53
|
+
.nullable()
|
|
54
|
+
.describe("A service tier advertised by the selected model; null uses its default."),
|
|
55
|
+
approvalPolicy,
|
|
56
|
+
approvalsReviewer,
|
|
57
|
+
permissionMode,
|
|
58
|
+
};
|
|
59
|
+
const tokenUsageBreakdown = z.object({
|
|
60
|
+
totalTokens: z.number(),
|
|
61
|
+
inputTokens: z.number(),
|
|
62
|
+
cachedInputTokens: z.number(),
|
|
63
|
+
cacheWriteInputTokens: z.number(),
|
|
64
|
+
outputTokens: z.number(),
|
|
65
|
+
reasoningOutputTokens: z.number(),
|
|
66
|
+
});
|
|
67
|
+
const tokenUsage = z.object({
|
|
68
|
+
total: tokenUsageBreakdown,
|
|
69
|
+
last: tokenUsageBreakdown,
|
|
70
|
+
modelContextWindow: z.number().nullable(),
|
|
71
|
+
});
|
|
72
|
+
const capabilities = z
|
|
73
|
+
.object({
|
|
74
|
+
namespaceTools: z.boolean(),
|
|
75
|
+
imageGeneration: z.boolean(),
|
|
76
|
+
webSearch: z.boolean(),
|
|
77
|
+
})
|
|
78
|
+
.catchall(z.boolean())
|
|
79
|
+
.nullable();
|
|
80
|
+
const session = z.object({
|
|
81
|
+
id: z.string(),
|
|
82
|
+
workspaceRoot: z.string(),
|
|
83
|
+
provider,
|
|
84
|
+
...settings,
|
|
85
|
+
tokenUsage: tokenUsage.nullable(),
|
|
86
|
+
status: z.enum(["idle", "running", "waiting_input", "error"]),
|
|
87
|
+
attention: z
|
|
88
|
+
.object({
|
|
89
|
+
kind: z.enum(["approval", "input"]),
|
|
90
|
+
count: z.number().int().positive(),
|
|
91
|
+
})
|
|
92
|
+
.nullable(),
|
|
93
|
+
createdAt: z.string(),
|
|
94
|
+
updatedAt: z.string(),
|
|
95
|
+
});
|
|
96
|
+
const turn = z.object({
|
|
97
|
+
id: z.string(),
|
|
98
|
+
sessionId: z.string(),
|
|
99
|
+
providerTurnId: z.string().nullable(),
|
|
100
|
+
provider,
|
|
101
|
+
...settings,
|
|
102
|
+
source: z.enum(["human", "mcp"]),
|
|
103
|
+
status: z.enum(["running", "completed", "interrupted", "failed"]),
|
|
104
|
+
usage: tokenUsageBreakdown.nullable(),
|
|
105
|
+
error: z
|
|
106
|
+
.object({
|
|
107
|
+
message: z.string(),
|
|
108
|
+
details: z.string().nullable(),
|
|
109
|
+
providerData: z.unknown().nullable(),
|
|
110
|
+
})
|
|
111
|
+
.nullable(),
|
|
112
|
+
startedAt: z.string(),
|
|
113
|
+
completedAt: z.string().nullable(),
|
|
114
|
+
});
|
|
115
|
+
const interactionResponse = z.discriminatedUnion("type", [
|
|
116
|
+
z.object({
|
|
117
|
+
type: z.literal("approval"),
|
|
118
|
+
decision: z.string().min(1),
|
|
119
|
+
}),
|
|
120
|
+
z.object({
|
|
121
|
+
type: z.literal("input"),
|
|
122
|
+
answers: z.record(z.string(), z.array(z.string())),
|
|
123
|
+
}),
|
|
124
|
+
]);
|
|
125
|
+
const interactionOption = z.object({
|
|
126
|
+
id: z.string(),
|
|
127
|
+
label: z.string(),
|
|
128
|
+
description: z.string().nullable(),
|
|
129
|
+
});
|
|
130
|
+
const itemBase = z.object({
|
|
131
|
+
id: z.string(),
|
|
132
|
+
turnId: z.string(),
|
|
133
|
+
providerItemId: z.string().nullable(),
|
|
134
|
+
sequence: z.number(),
|
|
135
|
+
status: z.enum(["running", "completed", "waiting", "interrupted", "failed"]),
|
|
136
|
+
createdAt: z.string(),
|
|
137
|
+
updatedAt: z.string(),
|
|
138
|
+
});
|
|
139
|
+
const item = z.discriminatedUnion("type", [
|
|
140
|
+
itemBase.extend({
|
|
141
|
+
type: z.literal("user_message"),
|
|
142
|
+
source: z.enum(["human", "mcp"]).optional(),
|
|
143
|
+
text: z.string(),
|
|
144
|
+
attachments: z.array(attachment),
|
|
145
|
+
}),
|
|
146
|
+
itemBase.extend({
|
|
147
|
+
type: z.literal("assistant_message"),
|
|
148
|
+
text: z.string(),
|
|
149
|
+
phase: z.enum(["commentary", "final_answer"]).nullable(),
|
|
150
|
+
}),
|
|
151
|
+
itemBase.extend({
|
|
152
|
+
type: z.literal("command"),
|
|
153
|
+
command: z.string(),
|
|
154
|
+
cwd: z.string().nullable(),
|
|
155
|
+
output: z.string(),
|
|
156
|
+
exitCode: z.number().nullable(),
|
|
157
|
+
}),
|
|
158
|
+
itemBase.extend({
|
|
159
|
+
type: z.literal("tool"),
|
|
160
|
+
progress: z.string().nullable(),
|
|
161
|
+
name: z.string(),
|
|
162
|
+
server: z.string().nullable(),
|
|
163
|
+
input: z.unknown(),
|
|
164
|
+
output: z.unknown(),
|
|
165
|
+
error: z.string().nullable(),
|
|
166
|
+
}),
|
|
167
|
+
itemBase.extend({ type: z.literal("turn_diff"), diff: z.string() }),
|
|
168
|
+
itemBase.extend({
|
|
169
|
+
type: z.literal("file_change"),
|
|
170
|
+
changes: z.array(z.object({
|
|
171
|
+
path: z.string(),
|
|
172
|
+
kind: z.string(),
|
|
173
|
+
movePath: z.string().nullable(),
|
|
174
|
+
diff: z.string(),
|
|
175
|
+
})),
|
|
176
|
+
}),
|
|
177
|
+
itemBase.extend({
|
|
178
|
+
type: z.literal("plan"),
|
|
179
|
+
text: z.string(),
|
|
180
|
+
steps: z.array(z.object({
|
|
181
|
+
step: z.string(),
|
|
182
|
+
status: z.enum(["pending", "inProgress", "completed"]),
|
|
183
|
+
})),
|
|
184
|
+
}),
|
|
185
|
+
itemBase.extend({ type: z.literal("reasoning_summary"), text: z.string() }),
|
|
186
|
+
itemBase.extend({
|
|
187
|
+
type: z.literal("artifact"),
|
|
188
|
+
artifact: attachment.extend({ kind: z.enum(["image", "file"]) }),
|
|
189
|
+
}),
|
|
190
|
+
itemBase.extend({
|
|
191
|
+
type: z.literal("interaction"),
|
|
192
|
+
interaction: z.object({
|
|
193
|
+
kind: z.enum(["approval", "input"]),
|
|
194
|
+
title: z.string(),
|
|
195
|
+
description: z.string().nullable(),
|
|
196
|
+
questions: z.array(z.object({
|
|
197
|
+
id: z.string(),
|
|
198
|
+
label: z.string(),
|
|
199
|
+
question: z.string(),
|
|
200
|
+
options: z.array(interactionOption),
|
|
201
|
+
multiSelect: z.boolean(),
|
|
202
|
+
allowFreeText: z.boolean(),
|
|
203
|
+
secret: z.boolean(),
|
|
204
|
+
})),
|
|
205
|
+
approvalOptions: z.array(interactionOption),
|
|
206
|
+
response: interactionResponse.nullable(),
|
|
207
|
+
}),
|
|
208
|
+
}),
|
|
209
|
+
itemBase.extend({
|
|
210
|
+
type: z.literal("notice"),
|
|
211
|
+
level: z.enum(["info", "warning", "error"]),
|
|
212
|
+
text: z.string(),
|
|
213
|
+
}),
|
|
214
|
+
]);
|
|
215
|
+
function configurationPatch(input) {
|
|
216
|
+
const patch = {};
|
|
217
|
+
for (const key of [
|
|
218
|
+
"model",
|
|
219
|
+
"reasoningEffort",
|
|
220
|
+
"reasoningSummary",
|
|
221
|
+
"serviceTier",
|
|
222
|
+
"approvalPolicy",
|
|
223
|
+
"approvalsReviewer",
|
|
224
|
+
"permissionMode",
|
|
225
|
+
]) {
|
|
226
|
+
if (input[key] !== undefined)
|
|
227
|
+
Object.assign(patch, { [key]: input[key] });
|
|
228
|
+
}
|
|
229
|
+
return patch;
|
|
230
|
+
}
|
|
231
|
+
export function registerAgentTools(mcp, agents) {
|
|
232
|
+
mcp.registerTool("agent_providers", {
|
|
233
|
+
title: "List Agent providers",
|
|
234
|
+
description: "List registered Agent providers, availability, authentication state, runtime version, declared features, provider capabilities, and exact provider-native permission settings. Capabilities are null when unavailable.",
|
|
235
|
+
inputSchema: z.object({}),
|
|
236
|
+
outputSchema: z.object({
|
|
237
|
+
providers: z.array(z.object({
|
|
238
|
+
id: provider,
|
|
239
|
+
displayName: z.string(),
|
|
240
|
+
icon: z.string().nullable(),
|
|
241
|
+
features: z
|
|
242
|
+
.object({
|
|
243
|
+
nativeReview: z.boolean(),
|
|
244
|
+
steering: z.boolean(),
|
|
245
|
+
})
|
|
246
|
+
.catchall(z.boolean()),
|
|
247
|
+
nativeSettings: z.array(z.object({
|
|
248
|
+
id: z.enum([
|
|
249
|
+
"approvalPolicy",
|
|
250
|
+
"approvalsReviewer",
|
|
251
|
+
"permissionMode",
|
|
252
|
+
]),
|
|
253
|
+
defaultValue: z.string(),
|
|
254
|
+
options: z.array(z.object({
|
|
255
|
+
id: z.string(),
|
|
256
|
+
description: z.string().nullable(),
|
|
257
|
+
})),
|
|
258
|
+
granularFields: z.array(z.object({
|
|
259
|
+
id: z.string(),
|
|
260
|
+
description: z.string().nullable(),
|
|
261
|
+
})),
|
|
262
|
+
})),
|
|
263
|
+
installed: z.boolean(),
|
|
264
|
+
authenticated: z.boolean(),
|
|
265
|
+
version: z.string().nullable(),
|
|
266
|
+
error: z.string().nullable(),
|
|
267
|
+
capabilities,
|
|
268
|
+
})),
|
|
269
|
+
}),
|
|
270
|
+
annotations: closedRead,
|
|
271
|
+
action: "providers",
|
|
272
|
+
}, async () => ({ providers: await agents.providerStatuses() }));
|
|
273
|
+
mcp.registerTool("agent_provider_details", {
|
|
274
|
+
title: "Read Agent provider details",
|
|
275
|
+
description: "Read provider-owned configuration requirements and rate limits. Each field is nullable provider-owned JSON; null means unavailable.",
|
|
276
|
+
inputSchema: z.object({ provider }),
|
|
277
|
+
outputSchema: z.object({
|
|
278
|
+
configRequirements: z.unknown().nullable(),
|
|
279
|
+
rateLimits: z.unknown().nullable(),
|
|
280
|
+
accountUsage: z
|
|
281
|
+
.object({
|
|
282
|
+
subscriptionType: z.string().nullable(),
|
|
283
|
+
windows: z.array(z.object({
|
|
284
|
+
id: z.string(),
|
|
285
|
+
label: z.string().nullable(),
|
|
286
|
+
utilization: z.number().nullable(),
|
|
287
|
+
resetsAt: z.string().nullable(),
|
|
288
|
+
})),
|
|
289
|
+
extraUsage: z
|
|
290
|
+
.object({
|
|
291
|
+
enabled: z.boolean(),
|
|
292
|
+
monthlyLimit: z.number().nullable(),
|
|
293
|
+
usedCredits: z.number().nullable(),
|
|
294
|
+
utilization: z.number().nullable(),
|
|
295
|
+
currency: z.string().nullable(),
|
|
296
|
+
})
|
|
297
|
+
.nullable(),
|
|
298
|
+
updatedAt: z.string(),
|
|
299
|
+
})
|
|
300
|
+
.nullable(),
|
|
301
|
+
}),
|
|
302
|
+
annotations: closedRead,
|
|
303
|
+
action: "provider_details",
|
|
304
|
+
}, ({ provider }) => agents.providerDetails(provider));
|
|
305
|
+
mcp.registerTool("agent_models", {
|
|
306
|
+
title: "List Agent models",
|
|
307
|
+
description: "List provider models with advertised reasoning efforts, input modalities, service tiers, defaults, and upgrade metadata. Select supported settings from this catalog and check agent_providers capabilities before configuring a session.",
|
|
308
|
+
inputSchema: z.object({ provider }),
|
|
309
|
+
outputSchema: z.object({
|
|
310
|
+
models: z.array(z.object({
|
|
311
|
+
id: z.string(),
|
|
312
|
+
model: z.string(),
|
|
313
|
+
displayName: z.string(),
|
|
314
|
+
description: z.string(),
|
|
315
|
+
modelSpecialty: z.string().nullable(),
|
|
316
|
+
isDefault: z.boolean(),
|
|
317
|
+
upgrade: z.string().nullable(),
|
|
318
|
+
upgradeInfo: z.unknown().nullable(),
|
|
319
|
+
availabilityMessage: z.string().nullable(),
|
|
320
|
+
reasoningEfforts: z.array(z.object({ id: z.string(), description: z.string() })),
|
|
321
|
+
defaultReasoningEffort: z.string().nullable(),
|
|
322
|
+
reasoningSummaries: z.array(z.enum(["auto", "concise", "detailed", "none"])),
|
|
323
|
+
defaultReasoningSummary: z
|
|
324
|
+
.enum(["auto", "concise", "detailed", "none"])
|
|
325
|
+
.nullable(),
|
|
326
|
+
inputModalities: z.array(z.enum(["text", "image", "audio"])),
|
|
327
|
+
multiAgentVersion: z.string().nullable(),
|
|
328
|
+
serviceTiers: z.array(z.object({
|
|
329
|
+
id: z.string(),
|
|
330
|
+
name: z.string(),
|
|
331
|
+
description: z.string(),
|
|
332
|
+
})),
|
|
333
|
+
defaultServiceTier: z.string().nullable(),
|
|
334
|
+
availableAccessPrograms: z
|
|
335
|
+
.object({
|
|
336
|
+
cyber: z.array(z.string()),
|
|
337
|
+
})
|
|
338
|
+
.catchall(z.array(z.string()))
|
|
339
|
+
.nullable(),
|
|
340
|
+
})),
|
|
341
|
+
}),
|
|
342
|
+
annotations: closedRead,
|
|
343
|
+
action: "models",
|
|
344
|
+
}, async ({ provider }) => ({ models: await agents.models(provider) }));
|
|
345
|
+
mcp.registerTool("agent_sessions", {
|
|
346
|
+
title: "List Agent sessions",
|
|
347
|
+
description: "List ChatRoom Agent sessions shared by MCP and the Web UI.",
|
|
348
|
+
inputSchema: z.object({}),
|
|
349
|
+
outputSchema: z.object({ sessions: z.array(session) }),
|
|
350
|
+
annotations: closedRead,
|
|
351
|
+
action: "sessions",
|
|
352
|
+
}, () => ({ sessions: agents.listSessions() }));
|
|
353
|
+
mcp.registerTool("agent_create", {
|
|
354
|
+
title: "Create Agent session",
|
|
355
|
+
description: "Create an Agent session for a ChatRoom workspace using a registered provider. Choose settings from agent_models and agent_providers capabilities; omitted or null settings use provider/model defaults.",
|
|
356
|
+
inputSchema: z.object({
|
|
357
|
+
workspaceRoot: z.string().min(1),
|
|
358
|
+
provider,
|
|
359
|
+
model: settings.model.default(null),
|
|
360
|
+
reasoningEffort: settings.reasoningEffort.default(null),
|
|
361
|
+
reasoningSummary: settings.reasoningSummary.default(null),
|
|
362
|
+
serviceTier: settings.serviceTier.default(null),
|
|
363
|
+
approvalPolicy: settings.approvalPolicy.default(null),
|
|
364
|
+
approvalsReviewer: settings.approvalsReviewer.default(null),
|
|
365
|
+
permissionMode: settings.permissionMode.default(null),
|
|
366
|
+
}),
|
|
367
|
+
outputSchema: session,
|
|
368
|
+
annotations: destructiveLocalMutation,
|
|
369
|
+
action: "create",
|
|
370
|
+
}, (input) => agents.createSession(input));
|
|
371
|
+
mcp.registerTool("agent_send", {
|
|
372
|
+
title: "Send Agent instruction",
|
|
373
|
+
description: "Send an instruction to an existing Agent session. The turn is recorded as source=mcp and appears in the same Web UI conversation as human turns. Returns after the turn is started; use agent_history to inspect progress.",
|
|
374
|
+
inputSchema: z.object({
|
|
375
|
+
sessionId: z.string().min(1),
|
|
376
|
+
text: z.string().default(""),
|
|
377
|
+
attachments: z.array(attachment).default([]),
|
|
378
|
+
outputSchema: z
|
|
379
|
+
.unknown()
|
|
380
|
+
.nullable()
|
|
381
|
+
.default(null)
|
|
382
|
+
.describe("Provider-supported JSON schema constraining the final response for this turn; omitted or null requests no output constraint."),
|
|
383
|
+
}),
|
|
384
|
+
outputSchema: turn,
|
|
385
|
+
annotations: openWorldMutation,
|
|
386
|
+
action: "send",
|
|
387
|
+
}, (input) => agents.startTurn(input.sessionId, {
|
|
388
|
+
text: input.text,
|
|
389
|
+
attachments: input.attachments,
|
|
390
|
+
outputSchema: input.outputSchema,
|
|
391
|
+
}, "mcp"));
|
|
392
|
+
mcp.registerTool("agent_steer", {
|
|
393
|
+
title: "Steer active Agent turn",
|
|
394
|
+
description: "Steer the currently active turn with text and attachments. Requires an active turn and accepts no configuration override. Use agent_history to inspect progress.",
|
|
395
|
+
inputSchema: z.object({
|
|
396
|
+
sessionId: z.string().min(1),
|
|
397
|
+
text: z.string().default(""),
|
|
398
|
+
attachments: z.array(attachment).default([]),
|
|
399
|
+
}),
|
|
400
|
+
outputSchema: z.object({ ok: z.literal(true) }),
|
|
401
|
+
annotations: openWorldMutation,
|
|
402
|
+
action: "steer",
|
|
403
|
+
}, async ({ sessionId, text, attachments }) => {
|
|
404
|
+
await agents.steer(sessionId, {
|
|
405
|
+
text,
|
|
406
|
+
attachments,
|
|
407
|
+
}, "mcp");
|
|
408
|
+
return { ok: true };
|
|
409
|
+
});
|
|
410
|
+
mcp.registerTool("agent_review", {
|
|
411
|
+
title: "Start Agent review",
|
|
412
|
+
description: "Start an inline review in the existing Agent conversation for uncommitted changes, a base branch, a commit, or custom instructions. Uses the session settings and records source=mcp. Returns after the review turn starts; use agent_history to inspect progress.",
|
|
413
|
+
inputSchema: z.object({
|
|
414
|
+
sessionId: z.string().min(1),
|
|
415
|
+
target: z.discriminatedUnion("type", [
|
|
416
|
+
z.object({ type: z.literal("uncommittedChanges") }),
|
|
417
|
+
z.object({ type: z.literal("baseBranch"), branch: z.string() }),
|
|
418
|
+
z.object({
|
|
419
|
+
type: z.literal("commit"),
|
|
420
|
+
sha: z.string(),
|
|
421
|
+
title: z.string().nullable(),
|
|
422
|
+
}),
|
|
423
|
+
z.object({ type: z.literal("custom"), instructions: z.string() }),
|
|
424
|
+
]),
|
|
425
|
+
}),
|
|
426
|
+
outputSchema: turn,
|
|
427
|
+
annotations: openWorldMutation,
|
|
428
|
+
action: "review",
|
|
429
|
+
}, ({ sessionId, target }) => agents.startReview(sessionId, target, "mcp"));
|
|
430
|
+
mcp.registerTool("agent_history", {
|
|
431
|
+
title: "Read Agent history",
|
|
432
|
+
description: "Read one Agent conversation including human/MCP source, tool activity, file changes, artifacts, reasoning summaries, plans, and pending interactions with their offered approvalOptions.",
|
|
433
|
+
inputSchema: z.object({ sessionId: z.string().min(1) }),
|
|
434
|
+
outputSchema: z.object({
|
|
435
|
+
session,
|
|
436
|
+
turns: z.array(z.object({
|
|
437
|
+
turn,
|
|
438
|
+
items: z.array(item),
|
|
439
|
+
})),
|
|
440
|
+
}),
|
|
441
|
+
annotations: closedRead,
|
|
442
|
+
action: "history",
|
|
443
|
+
}, ({ sessionId }) => agents.history(sessionId));
|
|
444
|
+
mcp.registerTool("agent_configure", {
|
|
445
|
+
title: "Configure Agent session",
|
|
446
|
+
description: "Atomically update model settings and provider-native permission settings for subsequent turns. Codex uses approvalPolicy, approvalsReviewer and permissionMode (sandbox). Omitted fields retain current values; null resets a field to its provider default. Read agent_providers for the exact native options.",
|
|
447
|
+
inputSchema: z.object({
|
|
448
|
+
sessionId: z.string().min(1),
|
|
449
|
+
model: settings.model.optional(),
|
|
450
|
+
reasoningEffort: settings.reasoningEffort.optional(),
|
|
451
|
+
reasoningSummary: settings.reasoningSummary.optional(),
|
|
452
|
+
serviceTier: settings.serviceTier.optional(),
|
|
453
|
+
approvalPolicy: settings.approvalPolicy.optional(),
|
|
454
|
+
approvalsReviewer: settings.approvalsReviewer.optional(),
|
|
455
|
+
permissionMode: settings.permissionMode.optional(),
|
|
456
|
+
}),
|
|
457
|
+
outputSchema: session,
|
|
458
|
+
annotations: destructiveLocalMutation,
|
|
459
|
+
action: "configure",
|
|
460
|
+
}, ({ sessionId, ...patch }) => agents.configureSession(sessionId, configurationPatch(patch)));
|
|
461
|
+
mcp.registerTool("agent_respond", {
|
|
462
|
+
title: "Respond to Agent interaction",
|
|
463
|
+
description: "Answer a pending Agent approval or structured input request. For approval, read interaction.approvalOptions in agent_history and submit one offered option’s id as the decision string.",
|
|
464
|
+
inputSchema: z.object({
|
|
465
|
+
sessionId: z.string().min(1),
|
|
466
|
+
itemId: z.string().min(1),
|
|
467
|
+
response: interactionResponse,
|
|
468
|
+
}),
|
|
469
|
+
outputSchema: item,
|
|
470
|
+
annotations: openWorldMutation,
|
|
471
|
+
action: "respond",
|
|
472
|
+
}, ({ sessionId, itemId, response }) => agents.respondInteraction(sessionId, itemId, response));
|
|
473
|
+
mcp.registerTool("agent_interrupt", {
|
|
474
|
+
title: "Interrupt Agent",
|
|
475
|
+
description: "Interrupt the active turn of an Agent session.",
|
|
476
|
+
inputSchema: z.object({ sessionId: z.string().min(1) }),
|
|
477
|
+
outputSchema: z.object({ ok: z.literal(true) }),
|
|
478
|
+
annotations: destructiveLocalMutation,
|
|
479
|
+
action: "interrupt",
|
|
480
|
+
}, async ({ sessionId }) => {
|
|
481
|
+
await agents.interrupt(sessionId);
|
|
482
|
+
return { ok: true };
|
|
483
|
+
});
|
|
484
|
+
mcp.registerTool("agent_switch_provider", {
|
|
485
|
+
title: "Switch Agent provider",
|
|
486
|
+
description: "Switch the active provider for the same Agent conversation, preserving visible history and synchronizing cross-provider context. Configure model settings from agent_models and provider-native permission settings from agent_providers. Omitted settings restore the target provider’s saved settings, or use defaults on its first activation; null resets a setting to its provider default. Returns the active target provider’s settings.",
|
|
487
|
+
inputSchema: z.object({
|
|
488
|
+
sessionId: z.string().min(1),
|
|
489
|
+
provider,
|
|
490
|
+
model: settings.model.optional(),
|
|
491
|
+
reasoningEffort: settings.reasoningEffort.optional(),
|
|
492
|
+
reasoningSummary: settings.reasoningSummary.optional(),
|
|
493
|
+
serviceTier: settings.serviceTier.optional(),
|
|
494
|
+
approvalPolicy: settings.approvalPolicy.optional(),
|
|
495
|
+
approvalsReviewer: settings.approvalsReviewer.optional(),
|
|
496
|
+
permissionMode: settings.permissionMode.optional(),
|
|
497
|
+
}),
|
|
498
|
+
outputSchema: session,
|
|
499
|
+
annotations: destructiveLocalMutation,
|
|
500
|
+
action: "switch_provider",
|
|
501
|
+
}, ({ sessionId, provider, ...patch }) => agents.switchProvider(sessionId, provider, configurationPatch(patch)));
|
|
502
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { WorkspaceAccessToken } from "#app/workspace-access";
|
|
2
|
+
import { createServiceToken } from "#app/service-registry";
|
|
3
|
+
import { AgentRepository } from "./repository.js";
|
|
4
|
+
import { AgentRuntime } from "./runtime.js";
|
|
5
|
+
import { registerAgentTools } from "./mcp.js";
|
|
6
|
+
import { createAgentProviders } from "./providers/index.js";
|
|
7
|
+
export const AgentServiceToken = createServiceToken("agent");
|
|
8
|
+
export function createAgentPlugin() {
|
|
9
|
+
let runtime = null;
|
|
10
|
+
let attachmentCleanupTimer = null;
|
|
11
|
+
return {
|
|
12
|
+
id: "agent",
|
|
13
|
+
async activate(context) {
|
|
14
|
+
runtime = new AgentRuntime(new AgentRepository(context.database), context.services.require(WorkspaceAccessToken), context.events, createAgentProviders(context.logs));
|
|
15
|
+
await runtime.cleanupOrphanAttachments();
|
|
16
|
+
attachmentCleanupTimer = setInterval(() => {
|
|
17
|
+
void runtime?.cleanupOrphanAttachments().catch(() => undefined);
|
|
18
|
+
}, 24 * 60 * 60 * 1000);
|
|
19
|
+
attachmentCleanupTimer.unref();
|
|
20
|
+
context.services.provide(AgentServiceToken, runtime);
|
|
21
|
+
},
|
|
22
|
+
registerMcp(mcp) {
|
|
23
|
+
if (!runtime)
|
|
24
|
+
throw new Error("Agent plugin is not active");
|
|
25
|
+
registerAgentTools(mcp, runtime);
|
|
26
|
+
},
|
|
27
|
+
async deactivate() {
|
|
28
|
+
if (attachmentCleanupTimer)
|
|
29
|
+
clearInterval(attachmentCleanupTimer);
|
|
30
|
+
attachmentCleanupTimer = null;
|
|
31
|
+
await runtime?.close();
|
|
32
|
+
runtime = null;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|