@opengeni/contracts 0.15.0 → 0.19.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/index.d.ts +2633 -102
- package/dist/index.js +4026 -2135
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/codex-fleet-policy.ts +1405 -0
- package/src/event-preview.ts +25 -8
- package/src/index.ts +1206 -66
- package/src/retained-output.ts +339 -0
package/src/index.ts
CHANGED
|
@@ -22,6 +22,30 @@ export {
|
|
|
22
22
|
type SessionEventPayloadTruncation,
|
|
23
23
|
} from "./event-preview";
|
|
24
24
|
|
|
25
|
+
export {
|
|
26
|
+
RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
|
|
27
|
+
RETAINED_OUTPUT_MAX_PAGE_BYTES,
|
|
28
|
+
RETAINED_OUTPUT_RECEIPT_MAX_BYTES,
|
|
29
|
+
RetainedArtifactMetadataSchema,
|
|
30
|
+
RetainedArtifactReferenceSchema,
|
|
31
|
+
RetainedArtifactUnavailableSchema,
|
|
32
|
+
RetainedOutputEvidenceSchema,
|
|
33
|
+
RetainedOutputKind,
|
|
34
|
+
RetainedOutputUnavailableReason,
|
|
35
|
+
retainedArtifactReferenceFromFile,
|
|
36
|
+
retainedOutputUnavailable,
|
|
37
|
+
resolveRetainedOutputRange,
|
|
38
|
+
validateRetainedOutputEvidence,
|
|
39
|
+
type RetainedArtifactFileInput,
|
|
40
|
+
type RetainedArtifactMetadata,
|
|
41
|
+
type RetainedArtifactReference,
|
|
42
|
+
type RetainedArtifactUnavailable,
|
|
43
|
+
type RetainedOutputAvailableEvidence,
|
|
44
|
+
type RetainedOutputEvidence,
|
|
45
|
+
type RetainedOutputRangeResolution,
|
|
46
|
+
type RetainedOutputResolvedRange,
|
|
47
|
+
} from "./retained-output";
|
|
48
|
+
|
|
25
49
|
export const SessionStatus = z.enum([
|
|
26
50
|
"queued",
|
|
27
51
|
"running",
|
|
@@ -444,6 +468,8 @@ export const ErrorCode = z.enum([
|
|
|
444
468
|
"conflict",
|
|
445
469
|
"idempotency_conflict",
|
|
446
470
|
"limit_exceeded",
|
|
471
|
+
"nested_agent_depth_exceeded",
|
|
472
|
+
"nested_agent_depth_override_forbidden",
|
|
447
473
|
"provider_verification_failed",
|
|
448
474
|
"upstream_unavailable",
|
|
449
475
|
"internal_error",
|
|
@@ -460,6 +486,45 @@ export const ErrorEnvelope = z.object({
|
|
|
460
486
|
});
|
|
461
487
|
export type ErrorEnvelope = z.infer<typeof ErrorEnvelope>;
|
|
462
488
|
|
|
489
|
+
/** Physical ceiling of the PostgreSQL integer columns that persist depth policy. */
|
|
490
|
+
export const MAX_NESTED_AGENT_DEPTH = 2_147_483_647;
|
|
491
|
+
export const NestedAgentDepthValue = z.number().int().nonnegative().max(MAX_NESTED_AGENT_DEPTH);
|
|
492
|
+
export type NestedAgentDepthValue = z.infer<typeof NestedAgentDepthValue>;
|
|
493
|
+
/** A denied child can be one greater than the persisted PostgreSQL int ceiling. */
|
|
494
|
+
export const NestedAgentDepthAttemptValue = z
|
|
495
|
+
.number()
|
|
496
|
+
.int()
|
|
497
|
+
.nonnegative()
|
|
498
|
+
.max(MAX_NESTED_AGENT_DEPTH + 1);
|
|
499
|
+
|
|
500
|
+
export const NestedAgentDepthPolicySource = z.enum([
|
|
501
|
+
"session",
|
|
502
|
+
"workspace",
|
|
503
|
+
"deployment",
|
|
504
|
+
"default",
|
|
505
|
+
]);
|
|
506
|
+
export type NestedAgentDepthPolicySource = z.infer<typeof NestedAgentDepthPolicySource>;
|
|
507
|
+
|
|
508
|
+
/** Durable evidence for a session-create denial at the database admission boundary. */
|
|
509
|
+
export const SessionSpawnDenial = z.object({
|
|
510
|
+
id: z.string().uuid(),
|
|
511
|
+
accountId: z.string().uuid(),
|
|
512
|
+
workspaceId: z.string().uuid(),
|
|
513
|
+
parentSessionId: z.string().uuid().nullable(),
|
|
514
|
+
rootSessionId: z.string().uuid().nullable(),
|
|
515
|
+
currentDepth: NestedAgentDepthValue,
|
|
516
|
+
attemptedDepth: NestedAgentDepthAttemptValue,
|
|
517
|
+
effectiveMaxNestedAgentDepth: NestedAgentDepthValue,
|
|
518
|
+
requestedMaxNestedAgentDepthOverride: NestedAgentDepthValue.nullable(),
|
|
519
|
+
policySource: NestedAgentDepthPolicySource,
|
|
520
|
+
policySessionId: z.string().uuid().nullable(),
|
|
521
|
+
subjectId: z.string().nullable(),
|
|
522
|
+
code: z.enum(["nested_agent_depth_exceeded", "nested_agent_depth_override_forbidden"]),
|
|
523
|
+
idempotencyKey: z.string().nullable(),
|
|
524
|
+
createdAt: z.string(),
|
|
525
|
+
});
|
|
526
|
+
export type SessionSpawnDenial = z.infer<typeof SessionSpawnDenial>;
|
|
527
|
+
|
|
463
528
|
export const Permission = z.enum([
|
|
464
529
|
"account:read",
|
|
465
530
|
"account:admin",
|
|
@@ -535,6 +600,30 @@ export const Permission = z.enum([
|
|
|
535
600
|
]);
|
|
536
601
|
export type Permission = z.infer<typeof Permission>;
|
|
537
602
|
|
|
603
|
+
/**
|
|
604
|
+
* Capability-first permissions signed into a session's first-party OpenGeni
|
|
605
|
+
* MCP token when a top-level creator does not explicitly narrow them.
|
|
606
|
+
*
|
|
607
|
+
* Keep this contract shared by admission and runtime signing: a worker-signed
|
|
608
|
+
* child whose parent was narrowed must inherit the parent's effective subset,
|
|
609
|
+
* never fall back to a different runtime-local default.
|
|
610
|
+
*/
|
|
611
|
+
export const DEFAULT_FIRST_PARTY_MCP_PERMISSIONS = [
|
|
612
|
+
"workspace:read",
|
|
613
|
+
"files:read",
|
|
614
|
+
"documents:search",
|
|
615
|
+
"scheduled_tasks:manage",
|
|
616
|
+
"scheduled_tasks:run",
|
|
617
|
+
"goals:manage",
|
|
618
|
+
"sessions:read",
|
|
619
|
+
"sessions:create",
|
|
620
|
+
"sessions:control",
|
|
621
|
+
"variable-sets:use",
|
|
622
|
+
"variable-sets:manage",
|
|
623
|
+
"rigs:use",
|
|
624
|
+
"github:use",
|
|
625
|
+
] as const satisfies readonly Permission[];
|
|
626
|
+
|
|
538
627
|
export function prefixedMcpToolName(registryId: string, toolName: string): string {
|
|
539
628
|
return `${registryId}__${toolName}`;
|
|
540
629
|
}
|
|
@@ -886,6 +975,9 @@ export const WorkspaceSettingsSchema = z
|
|
|
886
975
|
.object({
|
|
887
976
|
memoryEnabled: z.boolean().optional(),
|
|
888
977
|
transcription: WorkspaceTranscriptionPolicy.optional(),
|
|
978
|
+
// null clears the workspace override and falls back to the persisted
|
|
979
|
+
// deployment policy. The database boundary validates the same range.
|
|
980
|
+
maxNestedAgentDepth: NestedAgentDepthValue.nullable().optional(),
|
|
889
981
|
})
|
|
890
982
|
.passthrough();
|
|
891
983
|
export type WorkspaceSettings = z.infer<typeof WorkspaceSettingsSchema>;
|
|
@@ -903,6 +995,7 @@ export const UpdateWorkspaceSettingsRequest = z
|
|
|
903
995
|
.object({
|
|
904
996
|
memoryEnabled: z.boolean().optional(),
|
|
905
997
|
transcription: WorkspaceTranscriptionPolicy.optional(),
|
|
998
|
+
maxNestedAgentDepth: NestedAgentDepthValue.nullable().optional(),
|
|
906
999
|
})
|
|
907
1000
|
.passthrough();
|
|
908
1001
|
export type UpdateWorkspaceSettingsRequest = z.infer<typeof UpdateWorkspaceSettingsRequest>;
|
|
@@ -1737,11 +1830,39 @@ export type GitCredentialsRequest = {
|
|
|
1737
1830
|
repositoryIds: number[];
|
|
1738
1831
|
};
|
|
1739
1832
|
|
|
1833
|
+
/**
|
|
1834
|
+
* One exact repository route exposed by a host-owned HTTPS smart-Git broker.
|
|
1835
|
+
*
|
|
1836
|
+
* `repositoryUri` must echo one URI from the request's `repositoryRefs`.
|
|
1837
|
+
* `brokerUri` is a stable, credential-free HTTPS remote. The rotating bearer
|
|
1838
|
+
* remains separate in `GitCredentials.token`, so it cannot leak through Git
|
|
1839
|
+
* configuration, provider-CLI arguments, manifests, or repository metadata.
|
|
1840
|
+
*/
|
|
1841
|
+
export type GitHttpBrokerRepositoryRoute = {
|
|
1842
|
+
repositoryUri: string;
|
|
1843
|
+
brokerUri: string;
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1846
|
+
/**
|
|
1847
|
+
* Optional transport override for credentials that cannot be safely narrowed
|
|
1848
|
+
* into a provider token. Omission retains the provider-token behavior.
|
|
1849
|
+
*/
|
|
1850
|
+
export type GitCredentialTransport = {
|
|
1851
|
+
kind: "http_broker";
|
|
1852
|
+
repositories: GitHttpBrokerRepositoryRoute[];
|
|
1853
|
+
};
|
|
1854
|
+
|
|
1740
1855
|
export type GitCredentials = {
|
|
1741
|
-
// The minted
|
|
1742
|
-
//
|
|
1743
|
-
//
|
|
1856
|
+
// The minted secret. For the default transport this is a provider token; for
|
|
1857
|
+
// `http_broker` it is the broker bearer. Required for purpose="token";
|
|
1858
|
+
// optional for purpose="identity" so hosts can return only stable git identity
|
|
1859
|
+
// before lazy sandbox provision. The value never enters the manifest.
|
|
1744
1860
|
token?: string;
|
|
1861
|
+
// A host-owned exact smart-Git transport for providers whose available token
|
|
1862
|
+
// cannot be constrained to the selected repositories. OpenGeni rewrites only
|
|
1863
|
+
// the echoed repository remotes and never exposes this bearer to provider
|
|
1864
|
+
// CLIs. Omitted means the token is a direct provider credential.
|
|
1865
|
+
transport?: GitCredentialTransport;
|
|
1745
1866
|
// workspace-scope cross-check echo: the workspace the provider scoped this token to. The activity
|
|
1746
1867
|
// asserts `workspaceId === request.workspaceId` before injecting.
|
|
1747
1868
|
workspaceId: string;
|
|
@@ -1964,6 +2085,8 @@ export type McpCredentialsRequest = {
|
|
|
1964
2085
|
/** Immediate technical caller, retained only as non-authoritative audit context. */
|
|
1965
2086
|
callerSubjectId?: string;
|
|
1966
2087
|
surface: "model" | "toolspace";
|
|
2088
|
+
/** Canonical MCP destination that will receive the resolved headers. */
|
|
2089
|
+
destinationUrl: string;
|
|
1967
2090
|
serverId: string;
|
|
1968
2091
|
toolName?: string;
|
|
1969
2092
|
connectionRef: McpServerConnectionRef;
|
|
@@ -2604,6 +2727,63 @@ export const ToolRef = z.object({
|
|
|
2604
2727
|
export type ToolRef = z.infer<typeof ToolRef>;
|
|
2605
2728
|
|
|
2606
2729
|
const registryId = /^[A-Za-z0-9_-]+$/;
|
|
2730
|
+
export const SessionMcpServerId = z.string().min(1).regex(registryId);
|
|
2731
|
+
export type SessionMcpServerId = z.infer<typeof SessionMcpServerId>;
|
|
2732
|
+
|
|
2733
|
+
// How a session's persisted `tools` snapshot was selected. `legacy` is
|
|
2734
|
+
// reserved for rows written before this descriptor existed; those rows must
|
|
2735
|
+
// keep their materialized historical allow-list rather than being guessed to
|
|
2736
|
+
// mean either omitted or explicitly empty.
|
|
2737
|
+
export const SessionToolPolicy = z.object({
|
|
2738
|
+
mode: z.enum(["workspace_default", "explicit", "inherited", "legacy"]),
|
|
2739
|
+
inheritedFromSessionId: z.string().uuid().nullable(),
|
|
2740
|
+
});
|
|
2741
|
+
export type SessionToolPolicy = z.infer<typeof SessionToolPolicy>;
|
|
2742
|
+
|
|
2743
|
+
export const SESSION_EFFECTIVE_TOOL_POLICY_ID_LIMIT = 64;
|
|
2744
|
+
export const SESSION_EFFECTIVE_TOOL_POLICY_ID_MAX_LENGTH = 200;
|
|
2745
|
+
const SessionEffectiveToolPolicyId = z
|
|
2746
|
+
.string()
|
|
2747
|
+
.min(1)
|
|
2748
|
+
.max(SESSION_EFFECTIVE_TOOL_POLICY_ID_MAX_LENGTH)
|
|
2749
|
+
.regex(registryId);
|
|
2750
|
+
const SessionEffectiveToolPolicyIds = z
|
|
2751
|
+
.array(SessionEffectiveToolPolicyId)
|
|
2752
|
+
.max(SESSION_EFFECTIVE_TOOL_POLICY_ID_LIMIT);
|
|
2753
|
+
|
|
2754
|
+
// Secret-safe, read-time policy truth. This projection contains only bounded
|
|
2755
|
+
// MCP registry ids and exact counts: never URLs, names, headers, credentials,
|
|
2756
|
+
// connector configuration, or tool schemas. IDs are samples when capped;
|
|
2757
|
+
// counts remain exact and idsTruncated makes that explicit to clients.
|
|
2758
|
+
export const SessionEffectiveToolPolicy = z
|
|
2759
|
+
.object({
|
|
2760
|
+
mode: z.enum(["workspace_default", "explicit", "inherited", "legacy"]),
|
|
2761
|
+
inheritedFromSessionId: z.string().uuid().nullable(),
|
|
2762
|
+
selectedIds: SessionEffectiveToolPolicyIds,
|
|
2763
|
+
effectiveIds: SessionEffectiveToolPolicyIds,
|
|
2764
|
+
mandatoryIds: SessionEffectiveToolPolicyIds,
|
|
2765
|
+
lazyRouter: z
|
|
2766
|
+
.object({
|
|
2767
|
+
state: z.enum(["required", "disabled"]),
|
|
2768
|
+
deferredIds: SessionEffectiveToolPolicyIds,
|
|
2769
|
+
})
|
|
2770
|
+
.strict(),
|
|
2771
|
+
configuredIds: SessionEffectiveToolPolicyIds,
|
|
2772
|
+
droppedIds: SessionEffectiveToolPolicyIds,
|
|
2773
|
+
counts: z
|
|
2774
|
+
.object({
|
|
2775
|
+
selected: z.number().int().nonnegative(),
|
|
2776
|
+
effective: z.number().int().nonnegative(),
|
|
2777
|
+
mandatory: z.number().int().nonnegative(),
|
|
2778
|
+
deferred: z.number().int().nonnegative(),
|
|
2779
|
+
configured: z.number().int().nonnegative(),
|
|
2780
|
+
dropped: z.number().int().nonnegative(),
|
|
2781
|
+
})
|
|
2782
|
+
.strict(),
|
|
2783
|
+
idsTruncated: z.boolean(),
|
|
2784
|
+
})
|
|
2785
|
+
.strict();
|
|
2786
|
+
export type SessionEffectiveToolPolicy = z.infer<typeof SessionEffectiveToolPolicy>;
|
|
2607
2787
|
const httpsUrl = z
|
|
2608
2788
|
.string()
|
|
2609
2789
|
.url()
|
|
@@ -2618,19 +2798,54 @@ const httpsUrl = z
|
|
|
2618
2798
|
{ message: "URL must use https" },
|
|
2619
2799
|
);
|
|
2620
2800
|
|
|
2801
|
+
/**
|
|
2802
|
+
* Human-approval policy for one MCP server. `true` gates every tool, `false`
|
|
2803
|
+
* gates none, and a list gates only those unprefixed names.
|
|
2804
|
+
*/
|
|
2805
|
+
export const SESSION_MCP_APPROVAL_POLICY_MAX_TOOL_NAMES = 2_048;
|
|
2806
|
+
export const SESSION_MCP_APPROVAL_POLICY_MAX_BYTES = 256 * 1024;
|
|
2807
|
+
export const SESSION_MCP_APPROVAL_TOOL_NAME_MAX_BYTES = 1_024;
|
|
2808
|
+
export const SESSION_MCP_SERVERS_MAX = 64;
|
|
2809
|
+
|
|
2810
|
+
const sessionMcpApprovalToolName = z
|
|
2811
|
+
.string()
|
|
2812
|
+
.min(1)
|
|
2813
|
+
.superRefine((name, ctx) => {
|
|
2814
|
+
if (new TextEncoder().encode(name).byteLength > SESSION_MCP_APPROVAL_TOOL_NAME_MAX_BYTES) {
|
|
2815
|
+
ctx.addIssue({
|
|
2816
|
+
code: z.ZodIssueCode.custom,
|
|
2817
|
+
message: `MCP approval tool names must be at most ${SESSION_MCP_APPROVAL_TOOL_NAME_MAX_BYTES} UTF-8 bytes`,
|
|
2818
|
+
});
|
|
2819
|
+
}
|
|
2820
|
+
});
|
|
2821
|
+
const selectiveSessionMcpApprovalPolicy = z
|
|
2822
|
+
.array(sessionMcpApprovalToolName)
|
|
2823
|
+
.max(SESSION_MCP_APPROVAL_POLICY_MAX_TOOL_NAMES)
|
|
2824
|
+
.superRefine((names, ctx) => {
|
|
2825
|
+
const bytes = names.reduce(
|
|
2826
|
+
(total, name) => total + new TextEncoder().encode(name).byteLength,
|
|
2827
|
+
0,
|
|
2828
|
+
);
|
|
2829
|
+
if (bytes > SESSION_MCP_APPROVAL_POLICY_MAX_BYTES) {
|
|
2830
|
+
ctx.addIssue({
|
|
2831
|
+
code: z.ZodIssueCode.custom,
|
|
2832
|
+
message: `MCP approval policies must be at most ${SESSION_MCP_APPROVAL_POLICY_MAX_BYTES} UTF-8 bytes`,
|
|
2833
|
+
});
|
|
2834
|
+
}
|
|
2835
|
+
})
|
|
2836
|
+
.transform((names) => [...new Set(names)].sort());
|
|
2837
|
+
export const SessionMcpApprovalPolicy = z.union([z.boolean(), selectiveSessionMcpApprovalPolicy]);
|
|
2838
|
+
export type SessionMcpApprovalPolicy = z.infer<typeof SessionMcpApprovalPolicy>;
|
|
2839
|
+
|
|
2621
2840
|
export const SessionMcpServerInput = z.object({
|
|
2622
|
-
id:
|
|
2841
|
+
id: SessionMcpServerId,
|
|
2623
2842
|
name: z.string().min(1).optional(),
|
|
2624
2843
|
url: httpsUrl,
|
|
2625
2844
|
allowedTools: z.array(z.string().min(1)).optional(),
|
|
2626
2845
|
timeoutMs: z.number().int().positive().optional(),
|
|
2627
2846
|
cacheToolsList: z.boolean().optional(),
|
|
2628
|
-
//
|
|
2629
|
-
|
|
2630
|
-
// the caller resolves with `user.approvalDecision`); a string[] = ONLY the
|
|
2631
|
-
// listed UNPREFIXED tool names require approval (e.g. reads auto-run, writes
|
|
2632
|
-
// ask); absent / `false` = auto-run everything (the historical default).
|
|
2633
|
-
requireApproval: z.union([z.boolean(), z.array(z.string().min(1))]).optional(),
|
|
2847
|
+
// The caller resolves an approval pause with `user.approvalDecision`.
|
|
2848
|
+
requireApproval: SessionMcpApprovalPolicy.optional(),
|
|
2634
2849
|
// Write-only credential headers. Values are encrypted at rest and never
|
|
2635
2850
|
// returned in session responses or events; response metadata exposes names.
|
|
2636
2851
|
headers: z.record(z.string(), z.string()).optional(),
|
|
@@ -2641,23 +2856,43 @@ export const SessionMcpServerInput = z.object({
|
|
|
2641
2856
|
export type SessionMcpServerInput = z.infer<typeof SessionMcpServerInput>;
|
|
2642
2857
|
|
|
2643
2858
|
export const SessionMcpCredentialUpdateInput = z.object({
|
|
2644
|
-
id:
|
|
2859
|
+
id: SessionMcpServerId,
|
|
2645
2860
|
headers: z.record(z.string(), z.string()),
|
|
2646
2861
|
});
|
|
2647
2862
|
export type SessionMcpCredentialUpdateInput = z.infer<typeof SessionMcpCredentialUpdateInput>;
|
|
2648
2863
|
|
|
2649
2864
|
export const SessionMcpServerMetadata = z
|
|
2650
2865
|
.object({
|
|
2651
|
-
id:
|
|
2866
|
+
id: SessionMcpServerId,
|
|
2652
2867
|
name: z.string().min(1).nullable(),
|
|
2653
2868
|
url: httpsUrl,
|
|
2654
2869
|
headerNames: z.array(z.string()).default([]),
|
|
2655
2870
|
credentialVersion: z.number().int().positive(),
|
|
2871
|
+
requireApproval: SessionMcpApprovalPolicy.default(false),
|
|
2656
2872
|
connectionRef: McpServerConnectionRef.nullable().default(null),
|
|
2657
2873
|
})
|
|
2658
2874
|
.strict();
|
|
2659
2875
|
export type SessionMcpServerMetadata = z.infer<typeof SessionMcpServerMetadata>;
|
|
2660
2876
|
|
|
2877
|
+
export const UpdateSessionMcpApprovalPolicyRequest = z
|
|
2878
|
+
.object({
|
|
2879
|
+
requireApproval: SessionMcpApprovalPolicy,
|
|
2880
|
+
})
|
|
2881
|
+
.strict();
|
|
2882
|
+
export type UpdateSessionMcpApprovalPolicyRequest = z.infer<
|
|
2883
|
+
typeof UpdateSessionMcpApprovalPolicyRequest
|
|
2884
|
+
>;
|
|
2885
|
+
|
|
2886
|
+
export const UpdateSessionMcpApprovalPolicyResponse = z
|
|
2887
|
+
.object({
|
|
2888
|
+
server: SessionMcpServerMetadata,
|
|
2889
|
+
effectiveFrom: z.literal("next_attempt"),
|
|
2890
|
+
})
|
|
2891
|
+
.strict();
|
|
2892
|
+
export type UpdateSessionMcpApprovalPolicyResponse = z.infer<
|
|
2893
|
+
typeof UpdateSessionMcpApprovalPolicyResponse
|
|
2894
|
+
>;
|
|
2895
|
+
|
|
2661
2896
|
export class ResourceRefConflictError extends Error {
|
|
2662
2897
|
constructor(message: string) {
|
|
2663
2898
|
super(message);
|
|
@@ -2821,6 +3056,41 @@ export const SessionGoalPausedReason = z.enum([
|
|
|
2821
3056
|
]);
|
|
2822
3057
|
export type SessionGoalPausedReason = z.infer<typeof SessionGoalPausedReason>;
|
|
2823
3058
|
|
|
3059
|
+
export const SessionGoalContinuationState = z.enum([
|
|
3060
|
+
"inactive",
|
|
3061
|
+
"scheduled",
|
|
3062
|
+
"running",
|
|
3063
|
+
"blocked",
|
|
3064
|
+
"invariant_broken",
|
|
3065
|
+
]);
|
|
3066
|
+
export type SessionGoalContinuationState = z.infer<typeof SessionGoalContinuationState>;
|
|
3067
|
+
|
|
3068
|
+
export const SessionGoalContinuationReason = z.enum([
|
|
3069
|
+
"goal_inactive",
|
|
3070
|
+
"wake_pending",
|
|
3071
|
+
"continuation_pending",
|
|
3072
|
+
"human_work_pending",
|
|
3073
|
+
"goal_turn_running",
|
|
3074
|
+
"human_turn_running",
|
|
3075
|
+
"workstream_paused",
|
|
3076
|
+
"approval_required",
|
|
3077
|
+
"provider_backpressure",
|
|
3078
|
+
"session_cancelled",
|
|
3079
|
+
"system_work_pending",
|
|
3080
|
+
"missing_obligation",
|
|
3081
|
+
]);
|
|
3082
|
+
export type SessionGoalContinuationReason = z.infer<typeof SessionGoalContinuationReason>;
|
|
3083
|
+
|
|
3084
|
+
export const SessionGoalContinuation = z.object({
|
|
3085
|
+
state: SessionGoalContinuationState,
|
|
3086
|
+
reason: SessionGoalContinuationReason,
|
|
3087
|
+
wakeRevision: z.number().int().nonnegative(),
|
|
3088
|
+
observedRevision: z.number().int().nonnegative(),
|
|
3089
|
+
nextAttemptAt: z.string().datetime({ offset: true }).nullable(),
|
|
3090
|
+
lastError: z.string().nullable(),
|
|
3091
|
+
});
|
|
3092
|
+
export type SessionGoalContinuation = z.infer<typeof SessionGoalContinuation>;
|
|
3093
|
+
|
|
2824
3094
|
export const SessionGoal = z.object({
|
|
2825
3095
|
id: z.string().uuid(),
|
|
2826
3096
|
accountId: z.string().uuid(),
|
|
@@ -2838,6 +3108,9 @@ export const SessionGoal = z.object({
|
|
|
2838
3108
|
noProgressStreak: z.number().int().nonnegative(),
|
|
2839
3109
|
maxAutoContinuations: z.number().int().positive().nullable(),
|
|
2840
3110
|
metadata: z.record(z.string(), z.unknown()),
|
|
3111
|
+
// Optional for source compatibility with older clients; the API always
|
|
3112
|
+
// supplies this authoritative continuation projection.
|
|
3113
|
+
continuation: SessionGoalContinuation.optional(),
|
|
2841
3114
|
createdAt: z.string(),
|
|
2842
3115
|
updatedAt: z.string(),
|
|
2843
3116
|
});
|
|
@@ -3001,6 +3274,7 @@ export const SessionAuthorizationOperation = z.enum([
|
|
|
3001
3274
|
"session.human_input.read",
|
|
3002
3275
|
"session.human_input.write",
|
|
3003
3276
|
"session.title.write",
|
|
3277
|
+
"session.mcp.approval_policy.write",
|
|
3004
3278
|
"session.goal.read",
|
|
3005
3279
|
"session.goal.write",
|
|
3006
3280
|
"session.child.create",
|
|
@@ -3115,6 +3389,10 @@ export const SessionTurn = z.object({
|
|
|
3115
3389
|
prompt: z.string().min(1),
|
|
3116
3390
|
resources: z.array(ResourceRef),
|
|
3117
3391
|
tools: z.array(ToolRef),
|
|
3392
|
+
// Omitted/default discovery and explicit `tools: []` are distinct. False
|
|
3393
|
+
// inherits the durable session policy; true replaces it for this turn after
|
|
3394
|
+
// admission proves the selection is a subset.
|
|
3395
|
+
toolsProvided: z.boolean().optional(),
|
|
3118
3396
|
model: z.string().min(1),
|
|
3119
3397
|
reasoningEffort: ReasoningEffort,
|
|
3120
3398
|
sandboxBackend: SandboxBackend,
|
|
@@ -3204,6 +3482,9 @@ export const ComposerDraft = z.object({
|
|
|
3204
3482
|
text: z.string(),
|
|
3205
3483
|
resources: z.array(ResourceRef),
|
|
3206
3484
|
tools: z.array(ToolRef),
|
|
3485
|
+
// False means the draft inherits the session policy. True preserves an
|
|
3486
|
+
// explicit array, including [], across autosave/reload and queue checkout.
|
|
3487
|
+
toolsProvided: z.boolean().default(false),
|
|
3207
3488
|
model: z.string().min(1),
|
|
3208
3489
|
reasoningEffort: ReasoningEffort,
|
|
3209
3490
|
sourceTurnId: z.string().uuid().nullable(),
|
|
@@ -3260,11 +3541,51 @@ export const SaveComposerDraftRequest = ComposerDraft.pick({
|
|
|
3260
3541
|
text: true,
|
|
3261
3542
|
resources: true,
|
|
3262
3543
|
tools: true,
|
|
3544
|
+
toolsProvided: true,
|
|
3263
3545
|
model: true,
|
|
3264
3546
|
reasoningEffort: true,
|
|
3265
3547
|
}).extend({ expectedRevision: z.number().int().nonnegative() });
|
|
3266
3548
|
export type SaveComposerDraftRequest = z.infer<typeof SaveComposerDraftRequest>;
|
|
3267
3549
|
|
|
3550
|
+
/**
|
|
3551
|
+
* Create-only options saved with an actor's private pre-session draft. This is
|
|
3552
|
+
* deliberately narrower than CreateSessionRequest: idempotency/event keys and
|
|
3553
|
+
* credential-bearing MCP server inputs are per-attempt data, never draft state.
|
|
3554
|
+
*/
|
|
3555
|
+
export const NewSessionDraftOptions = z.object({
|
|
3556
|
+
sandboxBackend: SandboxBackend.optional(),
|
|
3557
|
+
targetSandboxId: z.string().uuid().optional(),
|
|
3558
|
+
workingDir: z.string().min(1).optional(),
|
|
3559
|
+
variableSetId: z.string().uuid().optional(),
|
|
3560
|
+
rigId: z.string().uuid().optional(),
|
|
3561
|
+
goal: GoalSpec.optional(),
|
|
3562
|
+
firstPartyMcpPermissions: z.array(Permission).optional(),
|
|
3563
|
+
});
|
|
3564
|
+
export type NewSessionDraftOptions = z.infer<typeof NewSessionDraftOptions>;
|
|
3565
|
+
|
|
3566
|
+
/** Actor-private, server-authoritative composer state before a session exists. */
|
|
3567
|
+
export const NewSessionDraft = z.object({
|
|
3568
|
+
revision: z.number().int().nonnegative(),
|
|
3569
|
+
text: z.string(),
|
|
3570
|
+
resources: z.array(ResourceRef),
|
|
3571
|
+
tools: z.array(ToolRef),
|
|
3572
|
+
model: z.string().min(1),
|
|
3573
|
+
reasoningEffort: ReasoningEffort,
|
|
3574
|
+
options: NewSessionDraftOptions,
|
|
3575
|
+
updatedAt: z.string().nullable(),
|
|
3576
|
+
});
|
|
3577
|
+
export type NewSessionDraft = z.infer<typeof NewSessionDraft>;
|
|
3578
|
+
|
|
3579
|
+
export const SaveNewSessionDraftRequest = NewSessionDraft.pick({
|
|
3580
|
+
text: true,
|
|
3581
|
+
resources: true,
|
|
3582
|
+
tools: true,
|
|
3583
|
+
model: true,
|
|
3584
|
+
reasoningEffort: true,
|
|
3585
|
+
options: true,
|
|
3586
|
+
}).extend({ expectedRevision: z.number().int().nonnegative() });
|
|
3587
|
+
export type SaveNewSessionDraftRequest = z.infer<typeof SaveNewSessionDraftRequest>;
|
|
3588
|
+
|
|
3268
3589
|
export const WORKSPACE_CONTROL_REASON_MAX_BYTES = 8 * 1024;
|
|
3269
3590
|
export const WORKSPACE_CONTROL_ACTOR_MAX_BYTES = 1024;
|
|
3270
3591
|
export const WORKSPACE_CONTROL_EVENT_MAX_BYTES = 16 * 1024;
|
|
@@ -3838,6 +4159,9 @@ export const ScheduledTaskAgentConfig = z.object({
|
|
|
3838
4159
|
reasoningEffort: ReasoningEffort.optional(),
|
|
3839
4160
|
sandboxBackend: SandboxBackend.optional(),
|
|
3840
4161
|
goal: GoalSpec.optional(),
|
|
4162
|
+
// Durable task override. Scheduled dispatch is trusted to preserve this
|
|
4163
|
+
// snapshot even if the workspace/deployment policy narrows later.
|
|
4164
|
+
maxNestedAgentDepth: NestedAgentDepthValue.optional(),
|
|
3841
4165
|
});
|
|
3842
4166
|
export type ScheduledTaskAgentConfig = z.infer<typeof ScheduledTaskAgentConfig>;
|
|
3843
4167
|
|
|
@@ -4355,6 +4679,19 @@ export const CapabilityRuntime = z.object({
|
|
|
4355
4679
|
mcpServerId: z.string().min(1).optional(),
|
|
4356
4680
|
transport: z.string().min(1).optional(),
|
|
4357
4681
|
notes: z.string().nullable().default(null),
|
|
4682
|
+
// Registry exposure provenance is server-derived and contains no endpoint or
|
|
4683
|
+
// credential material.
|
|
4684
|
+
catalogTrust: z
|
|
4685
|
+
.object({
|
|
4686
|
+
state: z.enum(["trusted", "legacy_active", "unverified"]),
|
|
4687
|
+
reason: z.enum([
|
|
4688
|
+
"trusted_source",
|
|
4689
|
+
"verified_probe",
|
|
4690
|
+
"active_installation_compatibility",
|
|
4691
|
+
"missing_verification",
|
|
4692
|
+
]),
|
|
4693
|
+
})
|
|
4694
|
+
.optional(),
|
|
4358
4695
|
});
|
|
4359
4696
|
export type CapabilityRuntime = z.infer<typeof CapabilityRuntime>;
|
|
4360
4697
|
|
|
@@ -4406,6 +4743,34 @@ export const CapabilityCatalogItem = z.object({
|
|
|
4406
4743
|
});
|
|
4407
4744
|
export type CapabilityCatalogItem = z.infer<typeof CapabilityCatalogItem>;
|
|
4408
4745
|
|
|
4746
|
+
/**
|
|
4747
|
+
* Shared trust gate for catalog visibility and runtime selection. Registry rows
|
|
4748
|
+
* remain durable for provenance and audit, but only a reviewed real-MCP probe
|
|
4749
|
+
* with known authentication is exposable. API-key rows additionally need a
|
|
4750
|
+
* machine-actionable header contract; prose credential instructions are not a
|
|
4751
|
+
* runtime contract and must fail closed.
|
|
4752
|
+
*/
|
|
4753
|
+
export function capabilityCatalogItemIsTrustedForExposure(
|
|
4754
|
+
item: Pick<CapabilityCatalogItem, "source" | "stale" | "authKind" | "metadata">,
|
|
4755
|
+
): boolean {
|
|
4756
|
+
if (item.stale) return false;
|
|
4757
|
+
if (item.source !== "registry") return true;
|
|
4758
|
+
const probe = item.metadata.mcpProbe;
|
|
4759
|
+
if (!probe || typeof probe !== "object" || Array.isArray(probe)) return false;
|
|
4760
|
+
if ((probe as Record<string, unknown>).status !== "real") return false;
|
|
4761
|
+
if (item.authKind === null || item.authKind === "unknown") return false;
|
|
4762
|
+
if (item.authKind !== "api_key") return true;
|
|
4763
|
+
const contract = item.metadata.authContract;
|
|
4764
|
+
if (!contract || typeof contract !== "object" || Array.isArray(contract)) return false;
|
|
4765
|
+
const record = contract as Record<string, unknown>;
|
|
4766
|
+
return (
|
|
4767
|
+
typeof record.headerName === "string" &&
|
|
4768
|
+
/^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/.test(record.headerName) &&
|
|
4769
|
+
typeof record.scheme === "string" &&
|
|
4770
|
+
record.scheme.trim().length > 0
|
|
4771
|
+
);
|
|
4772
|
+
}
|
|
4773
|
+
|
|
4409
4774
|
export const CapabilityInstallation = z.object({
|
|
4410
4775
|
id: z.string().uuid(),
|
|
4411
4776
|
accountId: z.string().uuid(),
|
|
@@ -4485,6 +4850,13 @@ export const Session = z.object({
|
|
|
4485
4850
|
instructions: z.string().nullable(),
|
|
4486
4851
|
resources: z.array(ResourceRef),
|
|
4487
4852
|
tools: z.array(ToolRef),
|
|
4853
|
+
// Origin of the persisted tool allow-list. Optional for rolling client
|
|
4854
|
+
// compatibility; current servers emit it and legacy rows map to `legacy`.
|
|
4855
|
+
toolPolicy: SessionToolPolicy.optional(),
|
|
4856
|
+
// Secret-safe current resolution, computed at an API/read or execution
|
|
4857
|
+
// boundary from IDs only. Optional because internal DB readers need not load
|
|
4858
|
+
// the workspace runtime registry.
|
|
4859
|
+
effectiveToolPolicy: SessionEffectiveToolPolicy.optional(),
|
|
4488
4860
|
metadata: z.record(z.string(), z.unknown()),
|
|
4489
4861
|
/** Frozen creator fact used only for creation attribution/idempotent repair. */
|
|
4490
4862
|
createdBy: TurnInitiator,
|
|
@@ -4525,6 +4897,14 @@ export const Session = z.object({
|
|
|
4525
4897
|
// direct API creates and scheduled-task runs. When set, this session's
|
|
4526
4898
|
// terminal-for-now transitions wake the parent.
|
|
4527
4899
|
parentSessionId: z.string().uuid().nullable(),
|
|
4900
|
+
// Server-authored nested-agent lineage/policy. Root sessions are depth 0;
|
|
4901
|
+
// snapshots are immutable and govern only future descendant creation.
|
|
4902
|
+
rootSessionId: z.string().uuid(),
|
|
4903
|
+
nestedAgentDepth: NestedAgentDepthValue,
|
|
4904
|
+
maxNestedAgentDepthOverride: NestedAgentDepthValue.nullable(),
|
|
4905
|
+
effectiveMaxNestedAgentDepth: NestedAgentDepthValue,
|
|
4906
|
+
nestedAgentDepthPolicySource: NestedAgentDepthPolicySource,
|
|
4907
|
+
nestedAgentDepthPolicySessionId: z.string().uuid().nullable(),
|
|
4528
4908
|
// Workspace-scoped CREATE idempotency key the session was created under (the
|
|
4529
4909
|
// dedup target collapsing double-submit/retry races to one session); null
|
|
4530
4910
|
// when the create carried no key.
|
|
@@ -4656,6 +5036,9 @@ export const SessionEventType = z.enum([
|
|
|
4656
5036
|
"agent.reasoning.delta",
|
|
4657
5037
|
"agent.toolCall.created",
|
|
4658
5038
|
"agent.toolCall.output",
|
|
5039
|
+
// Attempt-fenced Codex Responses lifecycle metadata (request identity,
|
|
5040
|
+
// deadlines, first-byte/terminal phase, provider request id). Never body/auth.
|
|
5041
|
+
"agent.model.request",
|
|
4659
5042
|
"agent.model.usage",
|
|
4660
5043
|
"tool.auth_needed",
|
|
4661
5044
|
"credential.auth_needed",
|
|
@@ -4719,6 +5102,7 @@ export const SessionEventType = z.enum([
|
|
|
4719
5102
|
"terminal.pty.output.delta", // PTY stdout/stderr bytes (separate from command.output)
|
|
4720
5103
|
"terminal.pty.exited", // PTY session ended (exitCode/reason)
|
|
4721
5104
|
"session.title_set",
|
|
5105
|
+
"session.mcp.approval_policy.updated",
|
|
4722
5106
|
// Multi-account Codex (P1): the account a session's turn runs on changed
|
|
4723
5107
|
// (manual switch in P1; failover/rotation in P3 reuse the same event). Drives
|
|
4724
5108
|
// the in-session "Running on:" indicator's live flip.
|
|
@@ -4726,6 +5110,10 @@ export const SessionEventType = z.enum([
|
|
|
4726
5110
|
// credential allocator per-turn selection audit. Payload is metadata only: credential row
|
|
4727
5111
|
// id, bounded strategy/reason, and pool counts — never token material.
|
|
4728
5112
|
"codex.credential.selected",
|
|
5113
|
+
// Adaptive fleet shadow decision record. Contains only bounded opaque candidate aliases,
|
|
5114
|
+
// normalized pressure/cache/confidence features, deterministic fingerprints,
|
|
5115
|
+
// the actual-vs-shadow comparison, and no credential/account identity.
|
|
5116
|
+
"codex.fleet.decision",
|
|
4729
5117
|
// credential allocator durable zero-capacity wait lifecycle. Runtime/system events only;
|
|
4730
5118
|
// no synthetic user message is created when capacity returns.
|
|
4731
5119
|
"codex.capacity.waiting",
|
|
@@ -4813,9 +5201,35 @@ export const SessionEventSemanticClass = z.enum([
|
|
|
4813
5201
|
]);
|
|
4814
5202
|
export type SessionEventSemanticClass = z.infer<typeof SessionEventSemanticClass>;
|
|
4815
5203
|
|
|
5204
|
+
/**
|
|
5205
|
+
* The semantic classes accepted by an exclusive latest lookup. `receipt` is
|
|
5206
|
+
* the concise public spelling for the historical `tool_receipt` class; the
|
|
5207
|
+
* latter remains accepted everywhere for backwards compatibility.
|
|
5208
|
+
*/
|
|
5209
|
+
export const SessionEventLatestClass = z.enum([
|
|
5210
|
+
"control",
|
|
5211
|
+
"terminal",
|
|
5212
|
+
"failure",
|
|
5213
|
+
"checkpoint",
|
|
5214
|
+
"tool_receipt",
|
|
5215
|
+
"provider_account",
|
|
5216
|
+
"receipt",
|
|
5217
|
+
]);
|
|
5218
|
+
export type SessionEventLatestClass = z.infer<typeof SessionEventLatestClass>;
|
|
5219
|
+
|
|
5220
|
+
export function sessionEventLatestClassToSemanticClass(
|
|
5221
|
+
value: SessionEventLatestClass,
|
|
5222
|
+
): SessionEventSemanticClass {
|
|
5223
|
+
return value === "receipt" ? "tool_receipt" : value;
|
|
5224
|
+
}
|
|
5225
|
+
|
|
4816
5226
|
export const SessionEventPayloadMode = z.enum(["none", "summary", "full"]);
|
|
4817
5227
|
export type SessionEventPayloadMode = z.infer<typeof SessionEventPayloadMode>;
|
|
4818
5228
|
|
|
5229
|
+
/** Select the compact semantic-result projection instead of an event array. */
|
|
5230
|
+
export const SessionEventResultMode = z.enum(["events", "compact"]);
|
|
5231
|
+
export type SessionEventResultMode = z.infer<typeof SessionEventResultMode>;
|
|
5232
|
+
|
|
4819
5233
|
export const SessionEventReadMode = z.enum(["monitoring", "forensic"]);
|
|
4820
5234
|
export type SessionEventReadMode = z.infer<typeof SessionEventReadMode>;
|
|
4821
5235
|
|
|
@@ -4853,9 +5267,11 @@ export const SESSION_EVENT_SEMANTIC_CLASS_TYPES = {
|
|
|
4853
5267
|
"workspace.inference.resumed",
|
|
4854
5268
|
"session.queue.changed",
|
|
4855
5269
|
"session.queue.prompt.cancelled",
|
|
5270
|
+
"session.mcp.approval_policy.updated",
|
|
4856
5271
|
],
|
|
4857
5272
|
terminal: [
|
|
4858
5273
|
"turn.completed",
|
|
5274
|
+
"agent.message.completed",
|
|
4859
5275
|
"turn.failed",
|
|
4860
5276
|
"turn.cancelled",
|
|
4861
5277
|
"turn.superseded",
|
|
@@ -5167,7 +5583,7 @@ export type TerminalPtyOutputDeltaPayload = z.infer<typeof TerminalPtyOutputDelt
|
|
|
5167
5583
|
export const TerminalPtyExitedPayload = z.object({
|
|
5168
5584
|
ptyId: z.string().uuid(),
|
|
5169
5585
|
exitCode: z.number().int().nullable(),
|
|
5170
|
-
reason: z.enum(["exit", "killed", "owner_gone", "timeout"]),
|
|
5586
|
+
reason: z.enum(["exit", "killed", "owner_gone", "timeout", "lost"]),
|
|
5171
5587
|
});
|
|
5172
5588
|
export type TerminalPtyExitedPayload = z.infer<typeof TerminalPtyExitedPayload>;
|
|
5173
5589
|
|
|
@@ -5626,7 +6042,8 @@ export type GitShowResponse = z.infer<typeof GitShowResponse>;
|
|
|
5626
6042
|
export const TerminalExecRequest = z.object({
|
|
5627
6043
|
command: z.string().min(1),
|
|
5628
6044
|
cwd: z.string().default(""), // workspace-relative
|
|
5629
|
-
//
|
|
6045
|
+
// Hard wall-clock bound. A timeout response is returned only after the exact
|
|
6046
|
+
// provider process is physically absent and any retained admission settles.
|
|
5630
6047
|
timeoutMs: z.number().int().positive().max(120_000).default(30_000),
|
|
5631
6048
|
// Stream the deltas onto A1 as the agent firehose (so other viewers see it),
|
|
5632
6049
|
// in addition to returning the buffered result inline.
|
|
@@ -5636,10 +6053,10 @@ export type TerminalExecRequest = z.infer<typeof TerminalExecRequest>;
|
|
|
5636
6053
|
export const TerminalExecResponse = z.object({
|
|
5637
6054
|
stdout: z.string(),
|
|
5638
6055
|
stderr: z.string(),
|
|
5639
|
-
exitCode: z.number().int()
|
|
5640
|
-
//
|
|
5641
|
-
//
|
|
5642
|
-
running: z.
|
|
6056
|
+
exitCode: z.number().int(),
|
|
6057
|
+
// Retained for wire compatibility; synchronous exec never exposes a live
|
|
6058
|
+
// provider process. Interactive work uses the PTY API.
|
|
6059
|
+
running: z.literal(false),
|
|
5643
6060
|
wallTimeSeconds: z.number().nonnegative(),
|
|
5644
6061
|
});
|
|
5645
6062
|
export type TerminalExecResponse = z.infer<typeof TerminalExecResponse>;
|
|
@@ -5709,6 +6126,354 @@ export const SessionEvent = z.object({
|
|
|
5709
6126
|
});
|
|
5710
6127
|
export type SessionEvent = z.infer<typeof SessionEvent>;
|
|
5711
6128
|
|
|
6129
|
+
export type SessionEventCompactResult = {
|
|
6130
|
+
version: 1;
|
|
6131
|
+
semanticClass: SessionEventSemanticClass;
|
|
6132
|
+
source: {
|
|
6133
|
+
id: string;
|
|
6134
|
+
type: SessionEventType;
|
|
6135
|
+
sequence: number;
|
|
6136
|
+
occurredAt: string;
|
|
6137
|
+
turnId: string | null;
|
|
6138
|
+
turnGeneration: number | null;
|
|
6139
|
+
turnAttemptId: string | null;
|
|
6140
|
+
turnAssociation: SessionEvent["turnAssociation"];
|
|
6141
|
+
};
|
|
6142
|
+
// These identity fields are repeated at the top level intentionally: an
|
|
6143
|
+
// MCP caller can act on the result without unpacking the source envelope.
|
|
6144
|
+
id: string;
|
|
6145
|
+
type: SessionEventType;
|
|
6146
|
+
sequence: number;
|
|
6147
|
+
occurredAt: string;
|
|
6148
|
+
turnId: string | null;
|
|
6149
|
+
turnGeneration: number | null;
|
|
6150
|
+
turnAttemptId: string | null;
|
|
6151
|
+
turnAssociation: SessionEvent["turnAssociation"];
|
|
6152
|
+
coveredSequence: { first: number; last: number };
|
|
6153
|
+
status:
|
|
6154
|
+
| "completed"
|
|
6155
|
+
| "failed"
|
|
6156
|
+
| "cancelled"
|
|
6157
|
+
| "superseded"
|
|
6158
|
+
| "checkpoint"
|
|
6159
|
+
| "receipt"
|
|
6160
|
+
| "unknown";
|
|
6161
|
+
text: string | null;
|
|
6162
|
+
output: unknown;
|
|
6163
|
+
result: unknown;
|
|
6164
|
+
failure: {
|
|
6165
|
+
error: string | null;
|
|
6166
|
+
code: string | null;
|
|
6167
|
+
retryable: boolean | null;
|
|
6168
|
+
recovery: string | null;
|
|
6169
|
+
} | null;
|
|
6170
|
+
checkpoint: unknown;
|
|
6171
|
+
receipt: unknown;
|
|
6172
|
+
truncation: {
|
|
6173
|
+
truncated: boolean;
|
|
6174
|
+
fields: string[];
|
|
6175
|
+
originalBytes: number | null;
|
|
6176
|
+
deliveredBytes: number;
|
|
6177
|
+
};
|
|
6178
|
+
};
|
|
6179
|
+
|
|
6180
|
+
const SESSION_EVENT_COMPACT_RESULT_TEXT_MAX_BYTES = 12 * 1024;
|
|
6181
|
+
// Five independently bounded slots plus identity/metadata must fit below the
|
|
6182
|
+
// 64 KiB MCP envelope even when a pathological producer supplies every slot.
|
|
6183
|
+
const SESSION_EVENT_COMPACT_RESULT_VALUE_MAX_BYTES = 8 * 1024;
|
|
6184
|
+
|
|
6185
|
+
type CompactValue = {
|
|
6186
|
+
value: unknown;
|
|
6187
|
+
truncated: boolean;
|
|
6188
|
+
originalBytes: number | null;
|
|
6189
|
+
};
|
|
6190
|
+
|
|
6191
|
+
type JsonRecord = Record<string, unknown>;
|
|
6192
|
+
|
|
6193
|
+
/**
|
|
6194
|
+
* Build the bounded semantic result used by `latest + result=compact`.
|
|
6195
|
+
*
|
|
6196
|
+
* This is intentionally a pure projection over one already-authoritative
|
|
6197
|
+
* event. It never reads history, invokes a model, follows a URL, or stores an
|
|
6198
|
+
* artifact. The DB/API/MCP layers decide which event is authoritative; this
|
|
6199
|
+
* helper only extracts the small result facts that can cross a client boundary.
|
|
6200
|
+
*/
|
|
6201
|
+
export function compactSessionEventResult(
|
|
6202
|
+
event: SessionEvent,
|
|
6203
|
+
semanticClass: SessionEventSemanticClass,
|
|
6204
|
+
coveredSequence: { first: number; last: number } = {
|
|
6205
|
+
first: event.sequence,
|
|
6206
|
+
last: event.sequence,
|
|
6207
|
+
},
|
|
6208
|
+
): SessionEventCompactResult {
|
|
6209
|
+
const payload = isSessionEventJsonRecord(event.payload) ? event.payload : {};
|
|
6210
|
+
const fields: string[] = [];
|
|
6211
|
+
let originalBytes = 0;
|
|
6212
|
+
|
|
6213
|
+
const textCandidate = typeof payload.text === "string" ? payload.text : null;
|
|
6214
|
+
const outputCandidate = Object.prototype.hasOwnProperty.call(payload, "output")
|
|
6215
|
+
? payload.output
|
|
6216
|
+
: null;
|
|
6217
|
+
const resultCandidate = Object.prototype.hasOwnProperty.call(payload, "result")
|
|
6218
|
+
? payload.result
|
|
6219
|
+
: undefined;
|
|
6220
|
+
const textValue = textCandidate ?? (typeof outputCandidate === "string" ? outputCandidate : null);
|
|
6221
|
+
const text = textValue === null ? null : compactResultText(textValue);
|
|
6222
|
+
if (text && text.truncated) {
|
|
6223
|
+
fields.push("text");
|
|
6224
|
+
originalBytes += text.originalBytes ?? 0;
|
|
6225
|
+
}
|
|
6226
|
+
|
|
6227
|
+
const output = compactResultValue(outputCandidate);
|
|
6228
|
+
if (outputCandidate !== null && output.truncated) {
|
|
6229
|
+
fields.push("output");
|
|
6230
|
+
originalBytes += output.originalBytes ?? 0;
|
|
6231
|
+
}
|
|
6232
|
+
|
|
6233
|
+
const result = compactResultValue(
|
|
6234
|
+
resultCandidate === undefined ? (textValue ?? outputCandidate) : resultCandidate,
|
|
6235
|
+
);
|
|
6236
|
+
if (resultCandidate !== undefined && result.truncated) {
|
|
6237
|
+
fields.push("result");
|
|
6238
|
+
originalBytes += result.originalBytes ?? 0;
|
|
6239
|
+
}
|
|
6240
|
+
|
|
6241
|
+
const checkpointField = firstOwnPayloadValue(payload, ["checkpoint", "summary", "snapshot"]);
|
|
6242
|
+
const checkpointCandidate =
|
|
6243
|
+
checkpointField !== undefined
|
|
6244
|
+
? checkpointField
|
|
6245
|
+
: semanticClass === "checkpoint"
|
|
6246
|
+
? payload
|
|
6247
|
+
: null;
|
|
6248
|
+
const checkpoint = compactResultValue(checkpointCandidate);
|
|
6249
|
+
if (checkpointCandidate !== null && checkpoint.truncated) {
|
|
6250
|
+
fields.push("checkpoint");
|
|
6251
|
+
originalBytes += checkpoint.originalBytes ?? 0;
|
|
6252
|
+
}
|
|
6253
|
+
|
|
6254
|
+
const receiptCandidate = firstOwnPayloadValue(payload, ["receipt", "receiptData"]);
|
|
6255
|
+
const receipt = compactResultValue(
|
|
6256
|
+
receiptCandidate !== undefined
|
|
6257
|
+
? receiptCandidate
|
|
6258
|
+
: semanticClass === "tool_receipt"
|
|
6259
|
+
? payload
|
|
6260
|
+
: null,
|
|
6261
|
+
);
|
|
6262
|
+
if (receipt.truncated) {
|
|
6263
|
+
fields.push("receipt");
|
|
6264
|
+
originalBytes += receipt.originalBytes ?? 0;
|
|
6265
|
+
}
|
|
6266
|
+
|
|
6267
|
+
const failure = compactFailure(payload, event.type);
|
|
6268
|
+
if (failure.truncated) {
|
|
6269
|
+
fields.push("failure");
|
|
6270
|
+
originalBytes += failure.originalBytes ?? 0;
|
|
6271
|
+
}
|
|
6272
|
+
|
|
6273
|
+
if (isSessionEventJsonRecord(payload.truncation) && payload.truncation.truncated === true) {
|
|
6274
|
+
fields.push("payload");
|
|
6275
|
+
}
|
|
6276
|
+
|
|
6277
|
+
const source = {
|
|
6278
|
+
id: event.id,
|
|
6279
|
+
type: event.type,
|
|
6280
|
+
sequence: event.sequence,
|
|
6281
|
+
occurredAt: event.occurredAt,
|
|
6282
|
+
turnId: event.turnId ?? null,
|
|
6283
|
+
turnGeneration: event.turnGeneration ?? null,
|
|
6284
|
+
turnAttemptId: event.turnAttemptId ?? null,
|
|
6285
|
+
turnAssociation: event.turnAssociation ?? null,
|
|
6286
|
+
};
|
|
6287
|
+
const status = compactResultStatus(event.type, semanticClass, payload);
|
|
6288
|
+
const outputValue = outputCandidate === null ? null : output.value;
|
|
6289
|
+
const resultValue = result.value;
|
|
6290
|
+
const checkpointValue = checkpointCandidate === null ? null : checkpoint.value;
|
|
6291
|
+
const receiptValue =
|
|
6292
|
+
receiptCandidate === null && semanticClass !== "tool_receipt" ? null : receipt.value;
|
|
6293
|
+
const compact: SessionEventCompactResult = {
|
|
6294
|
+
version: 1,
|
|
6295
|
+
semanticClass,
|
|
6296
|
+
source,
|
|
6297
|
+
id: source.id,
|
|
6298
|
+
type: source.type,
|
|
6299
|
+
sequence: source.sequence,
|
|
6300
|
+
occurredAt: source.occurredAt,
|
|
6301
|
+
turnId: source.turnId,
|
|
6302
|
+
turnGeneration: source.turnGeneration,
|
|
6303
|
+
turnAttemptId: source.turnAttemptId,
|
|
6304
|
+
turnAssociation: source.turnAssociation,
|
|
6305
|
+
coveredSequence,
|
|
6306
|
+
status,
|
|
6307
|
+
text: text?.value ?? null,
|
|
6308
|
+
output: outputValue,
|
|
6309
|
+
result: resultValue,
|
|
6310
|
+
failure: failure.value,
|
|
6311
|
+
checkpoint: checkpointValue,
|
|
6312
|
+
receipt: receiptValue,
|
|
6313
|
+
truncation: {
|
|
6314
|
+
truncated: fields.length > 0,
|
|
6315
|
+
fields: [...new Set(fields)],
|
|
6316
|
+
originalBytes: fields.length > 0 ? originalBytes || null : null,
|
|
6317
|
+
deliveredBytes: sessionEventJsonBytes({
|
|
6318
|
+
text: text?.value ?? null,
|
|
6319
|
+
output: outputValue,
|
|
6320
|
+
result: resultValue,
|
|
6321
|
+
failure: failure.value,
|
|
6322
|
+
checkpoint: checkpointValue,
|
|
6323
|
+
receipt: receiptValue,
|
|
6324
|
+
}),
|
|
6325
|
+
},
|
|
6326
|
+
};
|
|
6327
|
+
return compact;
|
|
6328
|
+
}
|
|
6329
|
+
|
|
6330
|
+
function isSessionEventJsonRecord(value: unknown): value is JsonRecord {
|
|
6331
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6332
|
+
}
|
|
6333
|
+
|
|
6334
|
+
function firstOwnPayloadValue(payload: JsonRecord, keys: readonly string[]): unknown | undefined {
|
|
6335
|
+
for (const key of keys) {
|
|
6336
|
+
if (Object.prototype.hasOwnProperty.call(payload, key)) return payload[key];
|
|
6337
|
+
}
|
|
6338
|
+
return undefined;
|
|
6339
|
+
}
|
|
6340
|
+
|
|
6341
|
+
function compactResultText(value: string): CompactValue & { value: string } {
|
|
6342
|
+
const originalBytes = new TextEncoder().encode(value).byteLength;
|
|
6343
|
+
if (originalBytes <= SESSION_EVENT_COMPACT_RESULT_TEXT_MAX_BYTES) {
|
|
6344
|
+
return { value, truncated: false, originalBytes };
|
|
6345
|
+
}
|
|
6346
|
+
let omittedBytes = originalBytes - SESSION_EVENT_COMPACT_RESULT_TEXT_MAX_BYTES;
|
|
6347
|
+
let projected = value;
|
|
6348
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
6349
|
+
const marker = `…[${omittedBytes} UTF-8 bytes omitted from compact result]…`;
|
|
6350
|
+
const budget = Math.max(0, SESSION_EVENT_COMPACT_RESULT_TEXT_MAX_BYTES - utf8Bytes(marker));
|
|
6351
|
+
const head = utf8PrefixForResult(value, Math.floor(budget * 0.7));
|
|
6352
|
+
const tail = utf8SuffixForResult(value, budget - utf8Bytes(head));
|
|
6353
|
+
projected = `${head}${marker}${tail}`;
|
|
6354
|
+
const nextOmitted = Math.max(0, originalBytes - utf8Bytes(head) - utf8Bytes(tail));
|
|
6355
|
+
if (nextOmitted === omittedBytes) break;
|
|
6356
|
+
omittedBytes = nextOmitted;
|
|
6357
|
+
}
|
|
6358
|
+
return { value: projected, truncated: true, originalBytes };
|
|
6359
|
+
}
|
|
6360
|
+
|
|
6361
|
+
function compactResultValue(value: unknown): CompactValue {
|
|
6362
|
+
if (value === null || value === undefined) {
|
|
6363
|
+
return { value: null, truncated: false, originalBytes: null };
|
|
6364
|
+
}
|
|
6365
|
+
const measurement = measureSessionEventJson(value);
|
|
6366
|
+
const bounded = boundSessionEventPayload(value, {
|
|
6367
|
+
surface: "http_projection",
|
|
6368
|
+
maxBytes: SESSION_EVENT_COMPACT_RESULT_VALUE_MAX_BYTES,
|
|
6369
|
+
});
|
|
6370
|
+
const deliveredBytes = measureSessionEventJson(bounded).bytes;
|
|
6371
|
+
return {
|
|
6372
|
+
value: bounded,
|
|
6373
|
+
truncated:
|
|
6374
|
+
measurement.bytes === null || deliveredBytes === null || measurement.bytes !== deliveredBytes,
|
|
6375
|
+
originalBytes: measurement.bytes,
|
|
6376
|
+
};
|
|
6377
|
+
}
|
|
6378
|
+
|
|
6379
|
+
function compactFailure(
|
|
6380
|
+
payload: JsonRecord,
|
|
6381
|
+
eventType: SessionEventType,
|
|
6382
|
+
): CompactValue & {
|
|
6383
|
+
value: SessionEventCompactResult["failure"];
|
|
6384
|
+
} {
|
|
6385
|
+
const isFailure =
|
|
6386
|
+
eventType === "turn.failed" ||
|
|
6387
|
+
eventType === "turn.cancelled" ||
|
|
6388
|
+
eventType === "turn.superseded";
|
|
6389
|
+
const hasFailureField = ["error", "code", "retryable", "recovery"].some((key) =>
|
|
6390
|
+
Object.prototype.hasOwnProperty.call(payload, key),
|
|
6391
|
+
);
|
|
6392
|
+
if (!isFailure && !hasFailureField) {
|
|
6393
|
+
return { value: null, truncated: false, originalBytes: null };
|
|
6394
|
+
}
|
|
6395
|
+
const error = compactResultStringField(payload.error);
|
|
6396
|
+
const code = compactResultStringField(payload.code);
|
|
6397
|
+
const recovery = compactResultStringField(payload.recovery);
|
|
6398
|
+
const retryable = typeof payload.retryable === "boolean" ? payload.retryable : null;
|
|
6399
|
+
const value = { error: error.value, code: code.value, retryable, recovery: recovery.value };
|
|
6400
|
+
const originalBytes = [error, code, recovery]
|
|
6401
|
+
.map((field) => field.originalBytes ?? 0)
|
|
6402
|
+
.reduce((sum, bytes) => sum + bytes, 0);
|
|
6403
|
+
return {
|
|
6404
|
+
value,
|
|
6405
|
+
truncated: error.truncated || code.truncated || recovery.truncated,
|
|
6406
|
+
originalBytes: originalBytes || null,
|
|
6407
|
+
};
|
|
6408
|
+
}
|
|
6409
|
+
|
|
6410
|
+
function compactResultStringField(value: unknown): CompactValue & { value: string | null } {
|
|
6411
|
+
if (typeof value !== "string") {
|
|
6412
|
+
return { value: null, truncated: false, originalBytes: null };
|
|
6413
|
+
}
|
|
6414
|
+
return compactResultText(value);
|
|
6415
|
+
}
|
|
6416
|
+
|
|
6417
|
+
function compactResultStatus(
|
|
6418
|
+
eventType: SessionEventType,
|
|
6419
|
+
semanticClass: SessionEventSemanticClass,
|
|
6420
|
+
payload: JsonRecord,
|
|
6421
|
+
): SessionEventCompactResult["status"] {
|
|
6422
|
+
if (eventType === "turn.failed") return "failed";
|
|
6423
|
+
if (eventType === "turn.cancelled") return "cancelled";
|
|
6424
|
+
if (eventType === "turn.superseded") return "superseded";
|
|
6425
|
+
if (eventType === "turn.completed" || eventType === "agent.message.completed") {
|
|
6426
|
+
return "completed";
|
|
6427
|
+
}
|
|
6428
|
+
if (semanticClass === "checkpoint") return "checkpoint";
|
|
6429
|
+
if (
|
|
6430
|
+
semanticClass === "tool_receipt" ||
|
|
6431
|
+
eventType === "artifact.created" ||
|
|
6432
|
+
eventType === "recording.available"
|
|
6433
|
+
) {
|
|
6434
|
+
return "receipt";
|
|
6435
|
+
}
|
|
6436
|
+
if (payload.status === "failed") return "failed";
|
|
6437
|
+
if (payload.status === "completed") return "completed";
|
|
6438
|
+
return "unknown";
|
|
6439
|
+
}
|
|
6440
|
+
|
|
6441
|
+
function utf8Bytes(value: string): number {
|
|
6442
|
+
return new TextEncoder().encode(value).byteLength;
|
|
6443
|
+
}
|
|
6444
|
+
|
|
6445
|
+
function utf8PrefixForResult(value: string, maxBytes: number): string {
|
|
6446
|
+
let bytes = 0;
|
|
6447
|
+
let index = 0;
|
|
6448
|
+
while (index < value.length) {
|
|
6449
|
+
const codePoint = value.codePointAt(index);
|
|
6450
|
+
if (codePoint === undefined) break;
|
|
6451
|
+
const character = String.fromCodePoint(codePoint);
|
|
6452
|
+
const next = utf8Bytes(character);
|
|
6453
|
+
if (bytes + next > maxBytes) break;
|
|
6454
|
+
bytes += next;
|
|
6455
|
+
index += character.length;
|
|
6456
|
+
}
|
|
6457
|
+
return value.slice(0, index);
|
|
6458
|
+
}
|
|
6459
|
+
|
|
6460
|
+
function utf8SuffixForResult(value: string, maxBytes: number): string {
|
|
6461
|
+
let bytes = 0;
|
|
6462
|
+
let index = value.length;
|
|
6463
|
+
while (index > 0) {
|
|
6464
|
+
const width =
|
|
6465
|
+
index > 1 && value.charCodeAt(index - 1) >= 0xdc00 && value.charCodeAt(index - 1) <= 0xdfff
|
|
6466
|
+
? 2
|
|
6467
|
+
: 1;
|
|
6468
|
+
const character = value.slice(index - width, index);
|
|
6469
|
+
const next = utf8Bytes(character);
|
|
6470
|
+
if (bytes + next > maxBytes) break;
|
|
6471
|
+
bytes += next;
|
|
6472
|
+
index -= width;
|
|
6473
|
+
}
|
|
6474
|
+
return value.slice(index);
|
|
6475
|
+
}
|
|
6476
|
+
|
|
5712
6477
|
// --- Durable host export ------------------------------------------------------
|
|
5713
6478
|
|
|
5714
6479
|
/** Wire revision for the durable host event/usage export stream. */
|
|
@@ -6388,6 +7153,14 @@ export const CreateSessionRequest = withVariableSetIdAlias({
|
|
|
6388
7153
|
// creation of a brand-new session. Absent means no create-dedup (each call
|
|
6389
7154
|
// is an independent create).
|
|
6390
7155
|
idempotencyKey: z.string().min(1).max(200).optional(),
|
|
7156
|
+
// The exact actor-private pre-session draft revision represented by this
|
|
7157
|
+
// create. The durable initializer consumes only this revision. A newer draft
|
|
7158
|
+
// written by a sibling tab survives, while every failed pre-initialization
|
|
7159
|
+
// create leaves the submitted draft intact.
|
|
7160
|
+
expectedNewSessionDraftRevision: z.number().int().nonnegative().optional(),
|
|
7161
|
+
// A child may lower its inherited limit freely; an increase requires
|
|
7162
|
+
// workspace:admin and is checked again at the DB transaction boundary.
|
|
7163
|
+
maxNestedAgentDepth: NestedAgentDepthValue.optional(),
|
|
6391
7164
|
// Permissions the session's first-party MCP token should carry. A top-level
|
|
6392
7165
|
// omission uses the deployment's worker default; a child omission inherits
|
|
6393
7166
|
// the creating session's effective grant. An explicit set is capped at
|
|
@@ -6401,7 +7174,7 @@ export const CreateSessionRequest = withVariableSetIdAlias({
|
|
|
6401
7174
|
// including [], are authoritative; non-empty explicit arrays require attach
|
|
6402
7175
|
// permission. Credential headers are write-only: create responses and events
|
|
6403
7176
|
// expose only SessionMcpServerMetadata.
|
|
6404
|
-
mcpServers: z.array(SessionMcpServerInput).default([]),
|
|
7177
|
+
mcpServers: z.array(SessionMcpServerInput).max(SESSION_MCP_SERVERS_MAX).default([]),
|
|
6405
7178
|
// Shared-sandbox placement (addendum 05 §D.1). Three-way union; OMITTED ⇒
|
|
6406
7179
|
// today's behavior (a context-dependent default resolved server-side: from
|
|
6407
7180
|
// inside a session → "shared" with the creator's box, top-level → "new").
|
|
@@ -6770,6 +7543,9 @@ export const SessionCapabilities = z.object({
|
|
|
6770
7543
|
liveness: z.enum(["cold", "warming", "warm", "draining"]),
|
|
6771
7544
|
// Echoed on viewer heartbeats (the split-brain fence).
|
|
6772
7545
|
leaseEpoch: z.number().int().nonnegative(),
|
|
7546
|
+
workspaceGeneration: z.number().int().nonnegative().nullable().default(null),
|
|
7547
|
+
archiveGeneration: z.number().int().nonnegative().nullable().default(null),
|
|
7548
|
+
archiveComplete: z.boolean().default(false),
|
|
6773
7549
|
viewerHeartbeatIntervalMs: z.number().int().positive().default(30_000),
|
|
6774
7550
|
FileSystem: z.object({
|
|
6775
7551
|
available: z.boolean(),
|
|
@@ -6874,6 +7650,9 @@ export const ViewerHolder = z.object({
|
|
|
6874
7650
|
liveness: z.enum(["cold", "warming", "warm", "draining"]),
|
|
6875
7651
|
// The epoch the viewer is fenced on; echoed back on heartbeats.
|
|
6876
7652
|
leaseEpoch: z.number().int().nonnegative(),
|
|
7653
|
+
workspaceGeneration: z.number().int().nonnegative().nullable(),
|
|
7654
|
+
archiveGeneration: z.number().int().nonnegative().nullable(),
|
|
7655
|
+
archiveComplete: z.boolean(),
|
|
6877
7656
|
viewerHeartbeatIntervalMs: z.number().int().positive(),
|
|
6878
7657
|
// The desktop pixel tunnel URL the viewer connects to directly; null until
|
|
6879
7658
|
// a viewer grant is minted (gated until then).
|
|
@@ -7237,6 +8016,9 @@ export const MachineView = z.object({
|
|
|
7237
8016
|
state: MachineState,
|
|
7238
8017
|
active: z.boolean(),
|
|
7239
8018
|
isSessionGroup: z.boolean(),
|
|
8019
|
+
workspaceGeneration: z.number().int().nonnegative().nullable(),
|
|
8020
|
+
archiveGeneration: z.number().int().nonnegative().nullable(),
|
|
8021
|
+
archiveComplete: z.boolean(),
|
|
7240
8022
|
os: z.string(),
|
|
7241
8023
|
arch: z.string(),
|
|
7242
8024
|
hasDisplay: z.boolean(),
|
|
@@ -7296,6 +8078,9 @@ export const SwapActiveSandboxResponse = z.object({
|
|
|
7296
8078
|
"unsupported_backend_context",
|
|
7297
8079
|
"transient_establishment",
|
|
7298
8080
|
"concurrent_swap",
|
|
8081
|
+
"recovery_in_progress",
|
|
8082
|
+
"recovery_degraded",
|
|
8083
|
+
"recovery_unrecoverable",
|
|
7299
8084
|
])
|
|
7300
8085
|
.optional(),
|
|
7301
8086
|
});
|
|
@@ -7310,6 +8095,239 @@ export const MachineMetricsSeriesResponse = z.object({
|
|
|
7310
8095
|
});
|
|
7311
8096
|
export type MachineMetricsSeriesResponse = z.infer<typeof MachineMetricsSeriesResponse>;
|
|
7312
8097
|
|
|
8098
|
+
/**
|
|
8099
|
+
* Keep this server-facing schema graph eager when imported while allowing
|
|
8100
|
+
* browser bundlers to discard it when contracts is used only for unrelated
|
|
8101
|
+
* helpers. Keep each call site annotated as pure; the factory argument itself
|
|
8102
|
+
* is side-effect-free until invoked.
|
|
8103
|
+
*/
|
|
8104
|
+
function defineModelContractSchema<Schema>(factory: () => Schema): Schema {
|
|
8105
|
+
return factory();
|
|
8106
|
+
}
|
|
8107
|
+
|
|
8108
|
+
export const ModelCapabilitySupportV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8109
|
+
z.enum(["supported", "unsupported", "unknown"]),
|
|
8110
|
+
);
|
|
8111
|
+
export type ModelCapabilitySupportV1 = z.infer<typeof ModelCapabilitySupportV1>;
|
|
8112
|
+
|
|
8113
|
+
export const ModelCapabilityStateV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8114
|
+
z.object({
|
|
8115
|
+
upstream: ModelCapabilitySupportV1,
|
|
8116
|
+
runnable: z.boolean(),
|
|
8117
|
+
}),
|
|
8118
|
+
);
|
|
8119
|
+
export type ModelCapabilityStateV1 = z.infer<typeof ModelCapabilityStateV1>;
|
|
8120
|
+
|
|
8121
|
+
export const ModelCapabilitiesV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8122
|
+
z.object({
|
|
8123
|
+
reasoning: ModelCapabilityStateV1.extend({
|
|
8124
|
+
efforts: z.array(ReasoningEffort),
|
|
8125
|
+
defaultEffort: ReasoningEffort.nullable(),
|
|
8126
|
+
required: z.boolean(),
|
|
8127
|
+
}),
|
|
8128
|
+
functionCalling: ModelCapabilityStateV1,
|
|
8129
|
+
structuredOutput: ModelCapabilityStateV1,
|
|
8130
|
+
hostedTools: z.object({
|
|
8131
|
+
webSearch: ModelCapabilityStateV1,
|
|
8132
|
+
xSearch: ModelCapabilityStateV1,
|
|
8133
|
+
codeExecution: ModelCapabilityStateV1,
|
|
8134
|
+
}),
|
|
8135
|
+
inputModalities: z.array(z.enum(["text", "image", "audio"])),
|
|
8136
|
+
outputModalities: z.array(z.enum(["text", "image", "audio"])),
|
|
8137
|
+
transports: z.object({
|
|
8138
|
+
sse: ModelCapabilityStateV1,
|
|
8139
|
+
responsesWebSocket: ModelCapabilityStateV1,
|
|
8140
|
+
realtimeAudio: ModelCapabilityStateV1,
|
|
8141
|
+
}),
|
|
8142
|
+
latencyModes: z.array(
|
|
8143
|
+
z.object({
|
|
8144
|
+
id: z.enum(["standard", "priority", "fast"]),
|
|
8145
|
+
upstream: ModelCapabilitySupportV1,
|
|
8146
|
+
runnable: z.boolean(),
|
|
8147
|
+
billingMultiplierBps: z.number().int().positive().optional(),
|
|
8148
|
+
}),
|
|
8149
|
+
),
|
|
8150
|
+
}),
|
|
8151
|
+
);
|
|
8152
|
+
export type ModelCapabilitiesV1 = z.infer<typeof ModelCapabilitiesV1>;
|
|
8153
|
+
|
|
8154
|
+
export const ModelCredentialSourceV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8155
|
+
z.union([
|
|
8156
|
+
z
|
|
8157
|
+
.object({ kind: z.literal("deployment"), mechanism: z.enum(["api_key", "azure_ad_bearer"]) })
|
|
8158
|
+
.strict(),
|
|
8159
|
+
z.object({ kind: z.literal("connected_subscription"), provider: z.literal("codex") }).strict(),
|
|
8160
|
+
z.object({ kind: z.literal("workspace_connection"), mechanism: z.literal("api_key") }).strict(),
|
|
8161
|
+
]),
|
|
8162
|
+
);
|
|
8163
|
+
export type ModelCredentialSourceV1 = z.infer<typeof ModelCredentialSourceV1>;
|
|
8164
|
+
|
|
8165
|
+
export const ModelBillingAttributionV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8166
|
+
z
|
|
8167
|
+
.object({
|
|
8168
|
+
upstreamPayer: z.enum(["deployment", "workspace", "connected_subscription"]),
|
|
8169
|
+
metering: z.enum(["opengeni_credits", "external"]),
|
|
8170
|
+
})
|
|
8171
|
+
.strict(),
|
|
8172
|
+
);
|
|
8173
|
+
export type ModelBillingAttributionV1 = z.infer<typeof ModelBillingAttributionV1>;
|
|
8174
|
+
|
|
8175
|
+
export const TURN_EXECUTION_POLICY_METADATA_KEY = "turnExecutionPolicyV1" as const;
|
|
8176
|
+
|
|
8177
|
+
export const TurnExecutionModelSourceV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8178
|
+
z.enum(["explicit", "session", "deployment", "continuation"]),
|
|
8179
|
+
);
|
|
8180
|
+
export type TurnExecutionModelSourceV1 = z.infer<typeof TurnExecutionModelSourceV1>;
|
|
8181
|
+
|
|
8182
|
+
export const TurnExecutionReasoningSourceV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8183
|
+
z.enum(["explicit", "session", "deployment", "continuation"]),
|
|
8184
|
+
);
|
|
8185
|
+
export type TurnExecutionReasoningSourceV1 = z.infer<typeof TurnExecutionReasoningSourceV1>;
|
|
8186
|
+
|
|
8187
|
+
/**
|
|
8188
|
+
* Secret-safe execution identity frozen onto one accepted logical turn.
|
|
8189
|
+
*
|
|
8190
|
+
* This is deliberately a strict, normalized reference to the deployment
|
|
8191
|
+
* definition rather than a serialized provider client. It must never contain
|
|
8192
|
+
* a key/token, concrete connected credential id, account label, authorization
|
|
8193
|
+
* header, or credential-bearing URL/query value.
|
|
8194
|
+
*/
|
|
8195
|
+
export const TurnExecutionPolicyV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8196
|
+
z
|
|
8197
|
+
.object({
|
|
8198
|
+
schemaVersion: z.literal(1),
|
|
8199
|
+
productModelId: z.string().min(1),
|
|
8200
|
+
requestedModelId: z.string().min(1).nullable(),
|
|
8201
|
+
modelSource: TurnExecutionModelSourceV1,
|
|
8202
|
+
reasoningEffort: ReasoningEffort,
|
|
8203
|
+
reasoningSource: TurnExecutionReasoningSourceV1,
|
|
8204
|
+
providerId: z.string().min(1),
|
|
8205
|
+
upstreamModelId: z.string().min(1),
|
|
8206
|
+
wireApi: z.enum(["responses", "chat"]),
|
|
8207
|
+
credentialSource: ModelCredentialSourceV1,
|
|
8208
|
+
billing: ModelBillingAttributionV1,
|
|
8209
|
+
definitionVersion: z.string().regex(/^sha256:[a-f0-9]{64}$/u),
|
|
8210
|
+
})
|
|
8211
|
+
.strict()
|
|
8212
|
+
.superRefine((policy, context) => {
|
|
8213
|
+
if (policy.modelSource === "explicit" && policy.requestedModelId === null) {
|
|
8214
|
+
context.addIssue({
|
|
8215
|
+
code: "custom",
|
|
8216
|
+
path: ["requestedModelId"],
|
|
8217
|
+
message: "an explicit model source requires a requested model id",
|
|
8218
|
+
});
|
|
8219
|
+
}
|
|
8220
|
+
if (policy.modelSource !== "explicit" && policy.requestedModelId !== null) {
|
|
8221
|
+
context.addIssue({
|
|
8222
|
+
code: "custom",
|
|
8223
|
+
path: ["requestedModelId"],
|
|
8224
|
+
message: "only an explicit model source may retain a requested model id",
|
|
8225
|
+
});
|
|
8226
|
+
}
|
|
8227
|
+
}),
|
|
8228
|
+
);
|
|
8229
|
+
export type TurnExecutionPolicyV1 = z.infer<typeof TurnExecutionPolicyV1>;
|
|
8230
|
+
|
|
8231
|
+
export type TurnExecutionPolicyReadV1 =
|
|
8232
|
+
| { kind: "absent" }
|
|
8233
|
+
| { kind: "valid"; policy: TurnExecutionPolicyV1 };
|
|
8234
|
+
|
|
8235
|
+
/**
|
|
8236
|
+
* Read the policy from turn metadata. Only a literally absent key is legacy;
|
|
8237
|
+
* null, undefined, an unknown schema version, extra fields, and every other
|
|
8238
|
+
* malformed present value fail closed. Error text reports paths only and never
|
|
8239
|
+
* reflects the untrusted value into logs or events.
|
|
8240
|
+
*/
|
|
8241
|
+
export function readTurnExecutionPolicyV1(metadata: unknown): TurnExecutionPolicyReadV1 {
|
|
8242
|
+
if (metadata === null || metadata === undefined) {
|
|
8243
|
+
return { kind: "absent" };
|
|
8244
|
+
}
|
|
8245
|
+
if (typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
8246
|
+
throw new Error("Malformed turn execution policy metadata: turn metadata is not an object");
|
|
8247
|
+
}
|
|
8248
|
+
const record = metadata as Record<string, unknown>;
|
|
8249
|
+
if (!Object.prototype.hasOwnProperty.call(record, TURN_EXECUTION_POLICY_METADATA_KEY)) {
|
|
8250
|
+
return { kind: "absent" };
|
|
8251
|
+
}
|
|
8252
|
+
const parsed = TurnExecutionPolicyV1.safeParse(record[TURN_EXECUTION_POLICY_METADATA_KEY]);
|
|
8253
|
+
if (!parsed.success) {
|
|
8254
|
+
const paths = [
|
|
8255
|
+
...new Set(
|
|
8256
|
+
parsed.error.issues.map((issue) =>
|
|
8257
|
+
issue.path.length === 0 ? "policy" : `policy.${issue.path.join(".")}`,
|
|
8258
|
+
),
|
|
8259
|
+
),
|
|
8260
|
+
].join(", ");
|
|
8261
|
+
throw new Error(`Malformed turn execution policy metadata at ${paths || "policy"}`);
|
|
8262
|
+
}
|
|
8263
|
+
return { kind: "valid", policy: parsed.data };
|
|
8264
|
+
}
|
|
8265
|
+
|
|
8266
|
+
/** Merge a trusted policy into metadata without disturbing dispatch/recovery state. */
|
|
8267
|
+
export function metadataWithTurnExecutionPolicyV1(
|
|
8268
|
+
metadata: Readonly<Record<string, unknown>> | null | undefined,
|
|
8269
|
+
policy: TurnExecutionPolicyV1,
|
|
8270
|
+
): Record<string, unknown> {
|
|
8271
|
+
return {
|
|
8272
|
+
...(metadata ?? {}),
|
|
8273
|
+
[TURN_EXECUTION_POLICY_METADATA_KEY]: TurnExecutionPolicyV1.parse(policy),
|
|
8274
|
+
};
|
|
8275
|
+
}
|
|
8276
|
+
|
|
8277
|
+
/**
|
|
8278
|
+
* Minimal, stable evidence projection for command receipts and audit events.
|
|
8279
|
+
* It intentionally excludes aliases, URLs, request metadata, and all concrete
|
|
8280
|
+
* credential-selection identity.
|
|
8281
|
+
*/
|
|
8282
|
+
export function turnExecutionPolicyAuditMetadata(
|
|
8283
|
+
policy: TurnExecutionPolicyV1,
|
|
8284
|
+
turnId: string,
|
|
8285
|
+
): Record<string, unknown> {
|
|
8286
|
+
const parsed = TurnExecutionPolicyV1.parse(policy);
|
|
8287
|
+
return {
|
|
8288
|
+
turnId,
|
|
8289
|
+
requestedModelId: parsed.requestedModelId,
|
|
8290
|
+
effectiveModelId: parsed.productModelId,
|
|
8291
|
+
modelSource: parsed.modelSource,
|
|
8292
|
+
effectiveReasoningEffort: parsed.reasoningEffort,
|
|
8293
|
+
reasoningSource: parsed.reasoningSource,
|
|
8294
|
+
providerId: parsed.providerId,
|
|
8295
|
+
credentialSourceKind: parsed.credentialSource.kind,
|
|
8296
|
+
credentialSourceMechanism:
|
|
8297
|
+
parsed.credentialSource.kind === "connected_subscription"
|
|
8298
|
+
? parsed.credentialSource.provider
|
|
8299
|
+
: parsed.credentialSource.mechanism,
|
|
8300
|
+
billingOwner: parsed.billing.upstreamPayer,
|
|
8301
|
+
billingMetering: parsed.billing.metering,
|
|
8302
|
+
definitionVersion: parsed.definitionVersion,
|
|
8303
|
+
};
|
|
8304
|
+
}
|
|
8305
|
+
|
|
8306
|
+
export const ModelPricingV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8307
|
+
z.object({
|
|
8308
|
+
inputMicrosPerMillionTokens: z.number().int().nonnegative(),
|
|
8309
|
+
cachedInputMicrosPerMillionTokens: z.number().int().nonnegative().optional(),
|
|
8310
|
+
outputMicrosPerMillionTokens: z.number().int().nonnegative(),
|
|
8311
|
+
marginBps: z.number().int().min(0).max(100_000).optional(),
|
|
8312
|
+
}),
|
|
8313
|
+
);
|
|
8314
|
+
export type ModelPricingV1 = z.infer<typeof ModelPricingV1>;
|
|
8315
|
+
|
|
8316
|
+
export const ModelPricingScheduleV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8317
|
+
z.object({
|
|
8318
|
+
default: ModelPricingV1,
|
|
8319
|
+
inputTokenTiers: z
|
|
8320
|
+
.array(
|
|
8321
|
+
z.object({
|
|
8322
|
+
minimumInputTokens: z.number().int().nonnegative(),
|
|
8323
|
+
pricing: ModelPricingV1,
|
|
8324
|
+
}),
|
|
8325
|
+
)
|
|
8326
|
+
.optional(),
|
|
8327
|
+
}),
|
|
8328
|
+
);
|
|
8329
|
+
export type ModelPricingScheduleV1 = z.infer<typeof ModelPricingScheduleV1>;
|
|
8330
|
+
|
|
7313
8331
|
/**
|
|
7314
8332
|
* A single host-exposed model + the provider that serves it, as surfaced to
|
|
7315
8333
|
* clients (SDK + React composer) by GET /v1/config/client. The wire `api`
|
|
@@ -7317,16 +8335,134 @@ export type MachineMetricsSeriesResponse = z.infer<typeof MachineMetricsSeriesRe
|
|
|
7317
8335
|
* provider id/label drive the picker's grouping. This mirrors the runtime's
|
|
7318
8336
|
* ConfiguredModel (packages/config) projected to the client-safe fields.
|
|
7319
8337
|
*/
|
|
7320
|
-
export const ClientModel =
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
8338
|
+
export const ClientModel = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8339
|
+
z.object({
|
|
8340
|
+
id: z.string(),
|
|
8341
|
+
label: z.string(),
|
|
8342
|
+
provider: z.string(), // provider id
|
|
8343
|
+
providerLabel: z.string(),
|
|
8344
|
+
api: z.enum(["responses", "chat"]),
|
|
8345
|
+
contextWindowTokens: z.number().int().positive().optional(),
|
|
8346
|
+
// Additive normalized definition metadata. Optional so older server payloads
|
|
8347
|
+
// remain parseable; current servers project the complete V1 set.
|
|
8348
|
+
schemaVersion: z.literal(1).optional(),
|
|
8349
|
+
aliases: z.array(z.string()).optional(),
|
|
8350
|
+
deployment: z
|
|
8351
|
+
.object({
|
|
8352
|
+
upstreamModelId: z.string().min(1),
|
|
8353
|
+
wireApi: z.enum(["responses", "chat"]),
|
|
8354
|
+
})
|
|
8355
|
+
.optional(),
|
|
8356
|
+
executionLimits: z
|
|
8357
|
+
.object({
|
|
8358
|
+
contextWindowTokens: z.number().int().positive().nullable(),
|
|
8359
|
+
effectiveContextWindowTokens: z.number().int().positive().nullable(),
|
|
8360
|
+
autoCompactTokenLimit: z.number().int().positive().nullable(),
|
|
8361
|
+
toolOutputTruncationTokens: z.number().int().positive().nullable(),
|
|
8362
|
+
})
|
|
8363
|
+
.optional(),
|
|
8364
|
+
credentialSource: ModelCredentialSourceV1.optional(),
|
|
8365
|
+
billing: ModelBillingAttributionV1.optional(),
|
|
8366
|
+
capabilities: ModelCapabilitiesV1.optional(),
|
|
8367
|
+
pricing: ModelPricingScheduleV1.optional(),
|
|
8368
|
+
definitionVersion: z
|
|
8369
|
+
.string()
|
|
8370
|
+
.regex(/^sha256:[a-f0-9]{64}$/u)
|
|
8371
|
+
.optional(),
|
|
8372
|
+
}),
|
|
8373
|
+
);
|
|
7328
8374
|
export type ClientModel = z.infer<typeof ClientModel>;
|
|
7329
8375
|
|
|
8376
|
+
export const ModelCredentialReadinessV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8377
|
+
z
|
|
8378
|
+
.object({
|
|
8379
|
+
status: z.enum(["ready", "not_ready", "error"]),
|
|
8380
|
+
reason: z
|
|
8381
|
+
.enum([
|
|
8382
|
+
"missing_credential",
|
|
8383
|
+
"needs_reauth",
|
|
8384
|
+
"prerequisites_missing",
|
|
8385
|
+
"resolver_error",
|
|
8386
|
+
"observation_stale",
|
|
8387
|
+
])
|
|
8388
|
+
.nullable(),
|
|
8389
|
+
basis: z.enum(["configuration", "connection", "resolver"]),
|
|
8390
|
+
checkedAt: z.string().datetime().nullable(),
|
|
8391
|
+
})
|
|
8392
|
+
.strict()
|
|
8393
|
+
.superRefine((readiness, context) => {
|
|
8394
|
+
if ((readiness.status === "ready") !== (readiness.reason === null)) {
|
|
8395
|
+
context.addIssue({
|
|
8396
|
+
code: "custom",
|
|
8397
|
+
path: ["reason"],
|
|
8398
|
+
message: "ready credential state requires no reason; non-ready state requires a reason",
|
|
8399
|
+
});
|
|
8400
|
+
}
|
|
8401
|
+
if ((readiness.status === "error") !== (readiness.reason === "resolver_error")) {
|
|
8402
|
+
context.addIssue({
|
|
8403
|
+
code: "custom",
|
|
8404
|
+
path: ["reason"],
|
|
8405
|
+
message:
|
|
8406
|
+
"credential errors require resolver_error and resolver_error requires error status",
|
|
8407
|
+
});
|
|
8408
|
+
}
|
|
8409
|
+
if (
|
|
8410
|
+
readiness.basis === "resolver" &&
|
|
8411
|
+
readiness.status === "ready" &&
|
|
8412
|
+
readiness.checkedAt === null
|
|
8413
|
+
) {
|
|
8414
|
+
context.addIssue({
|
|
8415
|
+
code: "custom",
|
|
8416
|
+
path: ["checkedAt"],
|
|
8417
|
+
message: "resolver readiness requires an observation timestamp",
|
|
8418
|
+
});
|
|
8419
|
+
}
|
|
8420
|
+
if (readiness.reason === "observation_stale" && readiness.checkedAt === null) {
|
|
8421
|
+
context.addIssue({
|
|
8422
|
+
code: "custom",
|
|
8423
|
+
path: ["checkedAt"],
|
|
8424
|
+
message: "a stale observation requires its observation timestamp",
|
|
8425
|
+
});
|
|
8426
|
+
}
|
|
8427
|
+
}),
|
|
8428
|
+
);
|
|
8429
|
+
export type ModelCredentialReadinessV1 = z.infer<typeof ModelCredentialReadinessV1>;
|
|
8430
|
+
|
|
8431
|
+
export const ModelAvailabilityV1 = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8432
|
+
z.object({
|
|
8433
|
+
status: z.enum(["available", "unavailable", "degraded", "unknown"]),
|
|
8434
|
+
selectable: z.boolean(),
|
|
8435
|
+
reason: z
|
|
8436
|
+
.enum([
|
|
8437
|
+
"missing_credential",
|
|
8438
|
+
"needs_reauth",
|
|
8439
|
+
"credential_not_ready",
|
|
8440
|
+
"not_entitled",
|
|
8441
|
+
"provider_unhealthy",
|
|
8442
|
+
"policy_blocked",
|
|
8443
|
+
"unsupported",
|
|
8444
|
+
])
|
|
8445
|
+
.nullable(),
|
|
8446
|
+
checkedAt: z.string().datetime().nullable(),
|
|
8447
|
+
}),
|
|
8448
|
+
);
|
|
8449
|
+
export type ModelAvailabilityV1 = z.infer<typeof ModelAvailabilityV1>;
|
|
8450
|
+
|
|
8451
|
+
export const WorkspaceModelCatalogModel = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8452
|
+
ClientModel.extend({
|
|
8453
|
+
credentialReadiness: ModelCredentialReadinessV1,
|
|
8454
|
+
availability: ModelAvailabilityV1,
|
|
8455
|
+
}),
|
|
8456
|
+
);
|
|
8457
|
+
export type WorkspaceModelCatalogModel = z.infer<typeof WorkspaceModelCatalogModel>;
|
|
8458
|
+
|
|
8459
|
+
export const WorkspaceModelCatalogResponse = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8460
|
+
z.object({
|
|
8461
|
+
models: z.array(WorkspaceModelCatalogModel),
|
|
8462
|
+
}),
|
|
8463
|
+
);
|
|
8464
|
+
export type WorkspaceModelCatalogResponse = z.infer<typeof WorkspaceModelCatalogResponse>;
|
|
8465
|
+
|
|
7330
8466
|
/**
|
|
7331
8467
|
* Exact public HTTP protocol revision spoken by this release train.
|
|
7332
8468
|
*
|
|
@@ -7338,46 +8474,48 @@ export type ClientModel = z.infer<typeof ClientModel>;
|
|
|
7338
8474
|
export const OPENGENI_API_CONTRACT_REVISION = "2026-07-turn-instructions-v1" as const;
|
|
7339
8475
|
export const OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract" as const;
|
|
7340
8476
|
|
|
7341
|
-
export const ClientConfig =
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
8477
|
+
export const ClientConfig = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
8478
|
+
z.object({
|
|
8479
|
+
deploymentRevision: z.string(),
|
|
8480
|
+
apiContractRevision: z.literal(OPENGENI_API_CONTRACT_REVISION),
|
|
8481
|
+
// Release-train version of the server (absent on dev/source builds). The
|
|
8482
|
+
// compatibility policy lives in docs/architecture.md — clients within the
|
|
8483
|
+
// same major are supported; evolution is additive within a major.
|
|
8484
|
+
serverVersion: z.string().optional(),
|
|
8485
|
+
defaultModel: z.string(),
|
|
8486
|
+
allowedModels: z.array(z.string()).min(1),
|
|
8487
|
+
// Richer model list (provider-grouped) for the picker. Defaults to [] for
|
|
8488
|
+
// back-compat: callers that only read allowedModels are unaffected.
|
|
8489
|
+
models: z.array(ClientModel).default([]),
|
|
8490
|
+
defaultReasoningEffort: ReasoningEffort,
|
|
8491
|
+
allowedReasoningEfforts: z.array(ReasoningEffort).min(1),
|
|
8492
|
+
mcpServers: z
|
|
8493
|
+
.array(
|
|
8494
|
+
z.object({
|
|
8495
|
+
id: z.string(),
|
|
8496
|
+
name: z.string(),
|
|
8497
|
+
}),
|
|
8498
|
+
)
|
|
8499
|
+
.default([]),
|
|
8500
|
+
fileUploads: z.object({
|
|
8501
|
+
enabled: z.boolean(),
|
|
8502
|
+
maxSizeBytes: z.number().int().positive(),
|
|
8503
|
+
}),
|
|
8504
|
+
productAccessMode: ProductAccessMode,
|
|
8505
|
+
auth: ClientAuthConfig.default({ mode: "none" }),
|
|
8506
|
+
// Server-wide hint: does this deployment support Channel-A structured services
|
|
8507
|
+
// at all (P4.4). Per-session availability is negotiated on /stream-capabilities
|
|
8508
|
+
// (it depends on the session's pinned backend); this is the coarse on/off the
|
|
8509
|
+
// client uses to decide whether to even attempt the fs/git/terminal panels.
|
|
8510
|
+
structuredServices: z
|
|
8511
|
+
.object({
|
|
8512
|
+
fileSystem: z.boolean(),
|
|
8513
|
+
git: z.boolean(),
|
|
8514
|
+
terminalEvents: z.boolean(),
|
|
8515
|
+
})
|
|
8516
|
+
.default({ fileSystem: false, git: false, terminalEvents: false }),
|
|
7366
8517
|
}),
|
|
7367
|
-
|
|
7368
|
-
auth: ClientAuthConfig.default({ mode: "none" }),
|
|
7369
|
-
// Server-wide hint: does this deployment support Channel-A structured services
|
|
7370
|
-
// at all (P4.4). Per-session availability is negotiated on /stream-capabilities
|
|
7371
|
-
// (it depends on the session's pinned backend); this is the coarse on/off the
|
|
7372
|
-
// client uses to decide whether to even attempt the fs/git/terminal panels.
|
|
7373
|
-
structuredServices: z
|
|
7374
|
-
.object({
|
|
7375
|
-
fileSystem: z.boolean(),
|
|
7376
|
-
git: z.boolean(),
|
|
7377
|
-
terminalEvents: z.boolean(),
|
|
7378
|
-
})
|
|
7379
|
-
.default({ fileSystem: false, git: false, terminalEvents: false }),
|
|
7380
|
-
});
|
|
8518
|
+
);
|
|
7381
8519
|
export type ClientConfig = z.infer<typeof ClientConfig>;
|
|
7382
8520
|
|
|
7383
8521
|
function base64UrlEncode(value: string): string {
|
|
@@ -7454,3 +8592,5 @@ export function evaluateWorkspaceModelPolicy(
|
|
|
7454
8592
|
}
|
|
7455
8593
|
return { allowed: true };
|
|
7456
8594
|
}
|
|
8595
|
+
|
|
8596
|
+
export * from "./codex-fleet-policy";
|