Skip to content

Commit 188b7a8

Browse files
feat: add protocol TIER-3 schemas (cli, client, mcp, custom-models, mission-decomposition) (#56)
Verbatim mirrors of the private factory-mono-alpha CLI/client wire protocol, extending the public source-of-truth protocol surface. Not yet wired into the public package API. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
1 parent 9e21239 commit 188b7a8

8 files changed

Lines changed: 2300 additions & 0 deletions

File tree

src/protocol/cli.ts

Lines changed: 563 additions & 0 deletions
Large diffs are not rendered by default.

src/protocol/client.ts

Lines changed: 1104 additions & 0 deletions
Large diffs are not rendered by default.

src/protocol/custom-models.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Source-of-truth mirror of factory-mono-alpha custom-model schemas (symbol-only).
2+
// Verbatim copy of CustomModelBedrockSchema, ManagedCustomModelSchema, and
3+
// CustomModelsSchema from packages/common/src/settings/schema.ts. Ported as-is
4+
// per the no-modification rule (includes apiKey / aws credential fields).
5+
// SandboxModeSchema is colocated here (one-liner from the same settings module).
6+
7+
import { z } from 'zod';
8+
9+
import { ModelProvider, ReasoningEffort, SandboxMode } from './enums.js';
10+
11+
const ReasoningEffortSchema = z.nativeEnum(ReasoningEffort);
12+
13+
export const SandboxModeSchema = z.nativeEnum(SandboxMode);
14+
15+
const CustomModelBedrockSchema = z.object({
16+
awsProfile: z.string().optional(),
17+
awsRegion: z.string().min(1).optional(),
18+
bedrockBaseUrl: z.string().url().optional(),
19+
awsAuthRefresh: z.string().optional(),
20+
awsCredentialExport: z.string().optional(),
21+
});
22+
23+
export const ManagedCustomModelSchema = z
24+
.object({
25+
model: z.string(),
26+
id: z.string().optional(),
27+
index: z.number().optional(),
28+
baseUrl: z.string().optional(),
29+
apiKey: z.string().optional(),
30+
provider: z.nativeEnum(ModelProvider),
31+
displayName: z.string().optional(),
32+
maxContextLimit: z.number().optional(),
33+
enableThinking: z.boolean().optional(),
34+
thinkingMaxTokens: z.number().optional(),
35+
maxOutputTokens: z.number().optional(),
36+
reasoningEffort: ReasoningEffortSchema.optional(),
37+
extraHeaders: z.record(z.string()).optional(),
38+
extraArgs: z.record(z.unknown()).optional(),
39+
noImageSupport: z.boolean().optional(),
40+
bedrock: CustomModelBedrockSchema.optional(),
41+
})
42+
.superRefine((model, ctx) => {
43+
if (model.provider === ModelProvider.BEDROCK_CONVERSE && !model.bedrock) {
44+
ctx.addIssue({
45+
code: z.ZodIssueCode.custom,
46+
path: ['bedrock'],
47+
message:
48+
'bedrock-converse custom models require a bedrock configuration block',
49+
});
50+
return;
51+
}
52+
if (model.bedrock) {
53+
if (
54+
model.provider !== ModelProvider.ANTHROPIC &&
55+
model.provider !== ModelProvider.BEDROCK_CONVERSE
56+
) {
57+
ctx.addIssue({
58+
code: z.ZodIssueCode.custom,
59+
path: ['provider'],
60+
message:
61+
'bedrock custom models require provider "anthropic" or "bedrock-converse"',
62+
});
63+
}
64+
return;
65+
}
66+
if (!model.baseUrl) {
67+
ctx.addIssue({
68+
code: z.ZodIssueCode.custom,
69+
path: ['baseUrl'],
70+
message: 'baseUrl is required unless bedrock is configured',
71+
});
72+
}
73+
if (!model.apiKey) {
74+
ctx.addIssue({
75+
code: z.ZodIssueCode.custom,
76+
path: ['apiKey'],
77+
message: 'apiKey is required unless bedrock is configured',
78+
});
79+
}
80+
});
81+
82+
export const CustomModelsSchema = z.array(ManagedCustomModelSchema);
83+
84+
export type ManagedCustomModel = z.infer<typeof ManagedCustomModelSchema>;
85+
export type CustomModels = z.infer<typeof CustomModelsSchema>;

src/protocol/enums.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,3 +585,50 @@ export enum ApiProvider {
585585
BASETEN = 'baseten',
586586
SNOWFLAKE = 'snowflake',
587587
}
588+
589+
export enum ModelKind {
590+
Concrete = 'concrete',
591+
Router = 'router',
592+
}
593+
594+
export enum LLMModelTier {
595+
Standard = 'standard',
596+
// Deprecated
597+
Premium = 'premium',
598+
// Extra Usage (overage) billing tier
599+
Overage = 'overage',
600+
}
601+
602+
// ---------------------------------------------------------------------------
603+
// settings/enums.ts (leaf subset)
604+
// ---------------------------------------------------------------------------
605+
606+
/**
607+
* Settings hierarchy level enum.
608+
* Precedence order (highest to lowest): Org -> Runtime -> Folder -> Project -> User
609+
*/
610+
export enum SettingsLevel {
611+
Org = 'org',
612+
Runtime = 'runtime',
613+
User = 'user',
614+
Project = 'project',
615+
Folder = 'folder',
616+
Dynamic = 'dynamic',
617+
BuiltIn = 'builtin',
618+
}
619+
620+
export enum DroidLocation {
621+
Project = 'project',
622+
Personal = 'personal',
623+
}
624+
625+
export enum SkillLocation {
626+
Project = 'project',
627+
Personal = 'personal',
628+
Builtin = 'builtin',
629+
}
630+
631+
export enum SandboxMode {
632+
PerCommand = 'per-command',
633+
WholeProcess = 'whole-process',
634+
}

src/protocol/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ export * from './messages.js';
1313
export * from './model-settings.js';
1414
export * from './loop.js';
1515
export * from './selectable-list-item.js';
16+
export * from './custom-models.js';
17+
export * from './mcp.js';
18+
export * from './mission-decomposition.js';
19+
export * from './cli.js';
20+
export * from './client.js';

src/protocol/mcp.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Source-of-truth mirror of factory-mono-alpha MCP schemas.
2+
// Verbatim copy of packages/common/src/droid/schemas/mcp.ts.
3+
4+
import { z } from 'zod';
5+
6+
import { McpServerStatus, McpServerType, SettingsLevel } from './enums.js';
7+
8+
// MCP primitives
9+
export const McpServerNameSchema = z.string();
10+
export const McpServerTypeSchema = z.enum(['stdio', 'http', 'sse']);
11+
12+
// Server config field schemas (used by registry and add-server requests)
13+
export const McpHttpServerConfigFieldsSchema = z.object({
14+
url: z.string().optional(),
15+
});
16+
17+
export const McpStdioServerConfigFieldsSchema = z.object({
18+
command: z.string().optional(),
19+
args: z.array(z.string()).optional(),
20+
});
21+
22+
// MCP server status (shared between LIST_MCP_SERVERS result and MCP_STATUS_CHANGED notification)
23+
export const McpServerStatusInfoSchema = z.object({
24+
name: z.string(),
25+
status: z.nativeEnum(McpServerStatus),
26+
source: z.nativeEnum(SettingsLevel),
27+
isManaged: z.boolean(),
28+
error: z.string().optional(),
29+
toolCount: z.number().optional(),
30+
serverType: z.nativeEnum(McpServerType),
31+
hasAuthTokens: z.boolean().optional(),
32+
requiresAuth: z.boolean().optional(),
33+
pendingAuthUrl: z.string().optional(),
34+
pendingAuthMessage: z.string().optional(),
35+
pendingAuthState: z.string().optional(),
36+
});
37+
38+
// MCP status summary (shared between LIST_MCP_SERVERS result and MCP_STATUS_CHANGED notification)
39+
export const McpStatusSummarySchema = z.object({
40+
total: z.number(),
41+
connected: z.number(),
42+
connecting: z.number(),
43+
failed: z.number(),
44+
disabled: z.number().optional(),
45+
});
46+
47+
// MCP registry server entity
48+
const McpRegistryServerBaseSchema = z.object({
49+
name: McpServerNameSchema,
50+
description: z.string(),
51+
type: McpServerTypeSchema,
52+
});
53+
54+
export const McpRegistryServerSchema = McpRegistryServerBaseSchema.merge(
55+
McpHttpServerConfigFieldsSchema
56+
)
57+
.merge(McpStdioServerConfigFieldsSchema)
58+
.extend({
59+
note: z.string().optional(),
60+
logoUrl: z.string().optional(),
61+
});
62+
63+
// MCP tool entity
64+
export const McpToolInfoSchema = z.object({
65+
serverName: McpServerNameSchema,
66+
name: z.string(),
67+
description: z.string().optional(),
68+
isEnabled: z.boolean(),
69+
isReadOnly: z.boolean().optional(),
70+
inputSchema: z
71+
.object({
72+
type: z.string().optional(),
73+
properties: z.record(z.unknown()).optional(),
74+
required: z.array(z.string()).optional(),
75+
})
76+
.optional(),
77+
});

0 commit comments

Comments
 (0)