@cleocode/contracts 2026.6.12 → 2026.6.14
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/__tests__/operation-def.test.js +5 -1
- package/dist/__tests__/operation-def.test.js.map +1 -1
- package/dist/__tests__/provider-def.test.d.ts +12 -0
- package/dist/__tests__/provider-def.test.d.ts.map +1 -0
- package/dist/__tests__/provider-def.test.js +84 -0
- package/dist/__tests__/provider-def.test.js.map +1 -0
- package/dist/__tests__/sealed-credential.test.d.ts +19 -0
- package/dist/__tests__/sealed-credential.test.d.ts.map +1 -0
- package/dist/__tests__/sealed-credential.test.js +74 -0
- package/dist/__tests__/sealed-credential.test.js.map +1 -0
- package/dist/__tests__/service-provider.test.d.ts +17 -0
- package/dist/__tests__/service-provider.test.d.ts.map +1 -0
- package/dist/__tests__/service-provider.test.js +108 -0
- package/dist/__tests__/service-provider.test.js.map +1 -0
- package/dist/__tests__/skill-executor-contract.test.js +3 -0
- package/dist/__tests__/skill-executor-contract.test.js.map +1 -1
- package/dist/acceptance-gate.d.ts +2 -3
- package/dist/acceptance-gate.d.ts.map +1 -1
- package/dist/boundary.d.ts +52 -0
- package/dist/boundary.d.ts.map +1 -1
- package/dist/boundary.js +24 -19
- package/dist/boundary.js.map +1 -1
- package/dist/conduit.d.ts +171 -0
- package/dist/conduit.d.ts.map +1 -1
- package/dist/config/index.d.ts +23 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +22 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config.d.ts +104 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/data-accessor.d.ts +21 -1
- package/dist/data-accessor.d.ts.map +1 -1
- package/dist/data-accessor.js.map +1 -1
- package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.d.ts +21 -0
- package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.d.ts.map +1 -0
- package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.js +84 -0
- package/dist/dispatch/__tests__/tasks-gateway-crud-ops.test.js.map +1 -0
- package/dist/dispatch/identity.d.ts +1 -1
- package/dist/dispatch/identity.d.ts.map +1 -1
- package/dist/dispatch/identity.js +25 -0
- package/dist/dispatch/identity.js.map +1 -1
- package/dist/dispatch/operation-def.d.ts +20 -0
- package/dist/dispatch/operation-def.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +1044 -182
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/docs/read.d.ts +2 -2
- package/dist/index.d.ts +25 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/lease-ipc/__tests__/freeze.test.d.ts +15 -0
- package/dist/lease-ipc/__tests__/freeze.test.d.ts.map +1 -0
- package/dist/lease-ipc/__tests__/freeze.test.js +313 -0
- package/dist/lease-ipc/__tests__/freeze.test.js.map +1 -0
- package/dist/lease-ipc/index.d.ts +17 -0
- package/dist/lease-ipc/index.d.ts.map +1 -0
- package/dist/lease-ipc/index.js +16 -0
- package/dist/lease-ipc/index.js.map +1 -0
- package/dist/lease-ipc/messages.d.ts +918 -0
- package/dist/lease-ipc/messages.d.ts.map +1 -0
- package/dist/lease-ipc/messages.js +476 -0
- package/dist/lease-ipc/messages.js.map +1 -0
- package/dist/lease-ipc/version.d.ts +41 -0
- package/dist/lease-ipc/version.d.ts.map +1 -0
- package/dist/lease-ipc/version.js +43 -0
- package/dist/lease-ipc/version.js.map +1 -0
- package/dist/llm/catalog-schema.d.ts +242 -0
- package/dist/llm/catalog-schema.d.ts.map +1 -0
- package/dist/llm/catalog-schema.js +153 -0
- package/dist/llm/catalog-schema.js.map +1 -0
- package/dist/llm/catalog-schema.json +139 -0
- package/dist/llm/index.d.ts +15 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +14 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/interfaces.d.ts +23 -0
- package/dist/llm/interfaces.d.ts.map +1 -1
- package/dist/llm/oauth.d.ts +16 -2
- package/dist/llm/oauth.d.ts.map +1 -1
- package/dist/llm/onboarding.d.ts +126 -0
- package/dist/llm/onboarding.d.ts.map +1 -0
- package/dist/llm/onboarding.js +34 -0
- package/dist/llm/onboarding.js.map +1 -0
- package/dist/llm/provider-def.d.ts +254 -0
- package/dist/llm/provider-def.d.ts.map +1 -0
- package/dist/llm/provider-def.js +93 -0
- package/dist/llm/provider-def.js.map +1 -0
- package/dist/llm/sealed-credential.d.ts +164 -0
- package/dist/llm/sealed-credential.d.ts.map +1 -0
- package/dist/llm/sealed-credential.js +43 -0
- package/dist/llm/sealed-credential.js.map +1 -0
- package/dist/llm/system-of-use.d.ts +383 -0
- package/dist/llm/system-of-use.d.ts.map +1 -0
- package/dist/llm/system-of-use.js +238 -0
- package/dist/llm/system-of-use.js.map +1 -0
- package/dist/llm/system-resolver.d.ts +87 -11
- package/dist/llm/system-resolver.d.ts.map +1 -1
- package/dist/llm/system-resolver.js +14 -7
- package/dist/llm/system-resolver.js.map +1 -1
- package/dist/operations/__tests__/ensures-schema-registry.test.d.ts +17 -0
- package/dist/operations/__tests__/ensures-schema-registry.test.d.ts.map +1 -0
- package/dist/operations/__tests__/ensures-schema-registry.test.js +113 -0
- package/dist/operations/__tests__/ensures-schema-registry.test.js.map +1 -0
- package/dist/operations/admin.d.ts +124 -1
- package/dist/operations/admin.d.ts.map +1 -1
- package/dist/operations/ensures-schema-registry.d.ts +172 -0
- package/dist/operations/ensures-schema-registry.d.ts.map +1 -0
- package/dist/operations/ensures-schema-registry.js +226 -0
- package/dist/operations/ensures-schema-registry.js.map +1 -0
- package/dist/operations/entities.d.ts +110 -0
- package/dist/operations/entities.d.ts.map +1 -0
- package/dist/operations/entities.js +695 -0
- package/dist/operations/entities.js.map +1 -0
- package/dist/operations/llm.d.ts +116 -9
- package/dist/operations/llm.d.ts.map +1 -1
- package/dist/operations/output-contracts-data.d.ts.map +1 -1
- package/dist/operations/output-contracts-data.js +230 -0
- package/dist/operations/output-contracts-data.js.map +1 -1
- package/dist/operations/service.d.ts +68 -0
- package/dist/operations/service.d.ts.map +1 -0
- package/dist/operations/service.js +336 -0
- package/dist/operations/service.js.map +1 -0
- package/dist/operations/tasks.d.ts +109 -0
- package/dist/operations/tasks.d.ts.map +1 -1
- package/dist/operations/tasks.js.map +1 -1
- package/dist/operations/validate.d.ts +1 -12
- package/dist/operations/validate.d.ts.map +1 -1
- package/dist/operations/validate.js +1 -1
- package/dist/playbook.d.ts +116 -0
- package/dist/playbook.d.ts.map +1 -1
- package/dist/release/plan.d.ts +5 -5
- package/dist/session.d.ts +11 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js.map +1 -1
- package/dist/templates/manifest.d.ts +1 -1
- package/dist/tools/agent-tools.d.ts +231 -0
- package/dist/tools/agent-tools.d.ts.map +1 -0
- package/dist/tools/agent-tools.js +25 -0
- package/dist/tools/agent-tools.js.map +1 -0
- package/dist/tools/atomic.d.ts +19 -0
- package/dist/tools/atomic.d.ts.map +1 -1
- package/dist/tools/atomic.js +17 -0
- package/dist/tools/atomic.js.map +1 -1
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/skill-executor.d.ts +7 -0
- package/dist/tools/skill-executor.d.ts.map +1 -1
- package/dist/tools/web-tools.d.ts +217 -0
- package/dist/tools/web-tools.d.ts.map +1 -0
- package/dist/tools/web-tools.js +31 -0
- package/dist/tools/web-tools.js.map +1 -0
- package/dist/vault/service-provider.d.ts +343 -0
- package/dist/vault/service-provider.d.ts.map +1 -0
- package/dist/vault/service-provider.js +857 -0
- package/dist/vault/service-provider.js.map +1 -0
- package/dist/workgraph.d.ts +12 -12
- package/package.json +14 -2
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/__tests__/operation-def.test.ts +7 -1
- package/src/__tests__/provider-def.test.ts +93 -0
- package/src/__tests__/sealed-credential.test.ts +100 -0
- package/src/__tests__/service-provider.test.ts +129 -0
- package/src/__tests__/skill-executor-contract.test.ts +3 -0
- package/src/acceptance-gate.ts +2 -3
- package/src/boundary.ts +70 -20
- package/src/conduit.ts +200 -0
- package/src/config/index.ts +35 -0
- package/src/config.ts +106 -1
- package/src/data-accessor.ts +22 -1
- package/src/dispatch/__tests__/tasks-gateway-crud-ops.test.ts +99 -0
- package/src/dispatch/identity.ts +25 -0
- package/src/dispatch/operation-def.ts +21 -0
- package/src/dispatch/operations-registry.ts +1083 -176
- package/src/index.ts +240 -25
- package/src/lease-ipc/__tests__/freeze.test.ts +342 -0
- package/src/lease-ipc/index.ts +75 -0
- package/src/lease-ipc/messages.ts +588 -0
- package/src/lease-ipc/version.ts +46 -0
- package/src/llm/catalog-schema.json +139 -0
- package/src/llm/catalog-schema.ts +184 -0
- package/src/llm/index.ts +29 -0
- package/src/llm/interfaces.ts +23 -0
- package/src/llm/oauth.ts +16 -2
- package/src/llm/onboarding.ts +131 -0
- package/src/llm/provider-def.ts +291 -0
- package/src/llm/sealed-credential.ts +166 -0
- package/src/llm/system-of-use.ts +503 -0
- package/src/llm/system-resolver.ts +91 -11
- package/src/operations/__tests__/ensures-schema-registry.test.ts +169 -0
- package/src/operations/admin.ts +144 -0
- package/src/operations/ensures-schema-registry.ts +260 -0
- package/src/operations/entities.ts +758 -0
- package/src/operations/llm.ts +120 -8
- package/src/operations/output-contracts-data.ts +264 -0
- package/src/operations/service.ts +360 -0
- package/src/operations/tasks.ts +119 -0
- package/src/operations/validate.ts +1 -14
- package/src/playbook.ts +117 -0
- package/src/session.ts +11 -0
- package/src/tools/agent-tools.ts +270 -0
- package/src/tools/atomic.ts +21 -0
- package/src/tools/index.ts +46 -0
- package/src/tools/skill-executor.ts +7 -0
- package/src/tools/web-tools.ts +247 -0
- package/src/vault/service-provider.ts +1137 -0
- package/dist/tessera.d.ts +0 -32
- package/dist/tessera.d.ts.map +0 -1
- package/dist/tessera.js +0 -11
- package/dist/tessera.js.map +0 -1
- package/dist/warp-chain.d.ts +0 -129
- package/dist/warp-chain.d.ts.map +0 -1
- package/dist/warp-chain.js +0 -13
- package/dist/warp-chain.js.map +0 -1
- package/src/tessera.ts +0 -35
- package/src/warp-chain.ts +0 -185
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-facing tool family I/O contracts (T1741 · epic T11456 · SG-TOOLS).
|
|
3
|
+
*
|
|
4
|
+
* The shared, types-only I/O shapes for the six CORE agent-tool families wired
|
|
5
|
+
* into the {@link ./atomic.js | atomic} primitive layer and surfaced through the
|
|
6
|
+
* `AgentToolRegistry` (`packages/core/src/tools/agent-registry.ts`):
|
|
7
|
+
*
|
|
8
|
+
* - **terminal** — `run_shell` with PTY + non-PTY modes ({@link RunShellInput}).
|
|
9
|
+
* - **file/read** — `read_file` with pagination ({@link ReadFilePagedInput}).
|
|
10
|
+
* - **file/patch** — `apply_patch` with fuzzy hunk matching ({@link ApplyPatchInput}).
|
|
11
|
+
* - **search** — `search_files` over ripgrep ({@link SearchFilesInput}).
|
|
12
|
+
* - **git** — status / diff / log / commit ({@link GitStatusInput} …).
|
|
13
|
+
*
|
|
14
|
+
* These compose OVER the atomic `fs`/`shell`/`search` primitives — they never
|
|
15
|
+
* introduce a new side-effect surface. The implementations
|
|
16
|
+
* (`packages/core/src/tools/builtin/*`) perform ALL work through the injected
|
|
17
|
+
* `GuardedToolSurface` (deny-first chokepoint), so the same guardrail policy
|
|
18
|
+
* applies. Types-only — no runtime logic (Gate 10 `contracts-purity`).
|
|
19
|
+
*
|
|
20
|
+
* @epic T11456
|
|
21
|
+
* @task T1741
|
|
22
|
+
* @see ./atomic.js — the raw primitive I/O shapes these compose over
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// terminal — run_shell (PTY + non-PTY)
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Execution mode for {@link RunShellInput}.
|
|
31
|
+
*
|
|
32
|
+
* - `pty` — allocate a pseudo-terminal (line-discipline, colour, interactive
|
|
33
|
+
* programs). Requires the OPTIONAL `node-pty` native dep; when it cannot be
|
|
34
|
+
* loaded the implementation transparently falls back to `spawn`.
|
|
35
|
+
* - `spawn` — plain `child_process.spawn` (no TTY). Always available.
|
|
36
|
+
* - `auto` — prefer `pty` when `node-pty` is loadable, else `spawn`.
|
|
37
|
+
*/
|
|
38
|
+
export type ShellRunMode = 'pty' | 'spawn' | 'auto';
|
|
39
|
+
|
|
40
|
+
/** Input for the `run_shell` terminal tool. */
|
|
41
|
+
export interface RunShellInput {
|
|
42
|
+
/** Executable to run (argv form — NOT a shell string; no shell interpolation). */
|
|
43
|
+
readonly command: string;
|
|
44
|
+
/** Arguments for {@link RunShellInput.command}. */
|
|
45
|
+
readonly args?: readonly string[];
|
|
46
|
+
/** Working directory. */
|
|
47
|
+
readonly cwd?: string;
|
|
48
|
+
/** Extra environment variables (scrubbed at the guard chokepoint). */
|
|
49
|
+
readonly env?: Readonly<Record<string, string>>;
|
|
50
|
+
/** Hard timeout in milliseconds; the process is killed when exceeded. */
|
|
51
|
+
readonly timeoutMs?: number;
|
|
52
|
+
/** Execution mode. Defaults to `auto`. */
|
|
53
|
+
readonly mode?: ShellRunMode;
|
|
54
|
+
/** PTY column count (PTY mode only). Defaults to 80. */
|
|
55
|
+
readonly cols?: number;
|
|
56
|
+
/** PTY row count (PTY mode only). Defaults to 24. */
|
|
57
|
+
readonly rows?: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Result of the `run_shell` terminal tool. */
|
|
61
|
+
export interface RunShellResult {
|
|
62
|
+
/**
|
|
63
|
+
* Combined output. In `spawn` mode this is stdout; in `pty` mode stdout and
|
|
64
|
+
* stderr are interleaved on the single PTY stream (as a real terminal does).
|
|
65
|
+
*/
|
|
66
|
+
readonly stdout: string;
|
|
67
|
+
/** Captured standard error. Empty in PTY mode (merged into {@link RunShellResult.stdout}). */
|
|
68
|
+
readonly stderr: string;
|
|
69
|
+
/** Process exit code (0 = success). `null` when killed by signal/timeout. */
|
|
70
|
+
readonly code: number | null;
|
|
71
|
+
/** The mode that actually ran (`pty` downgrades to `spawn` when unavailable). */
|
|
72
|
+
readonly mode: 'pty' | 'spawn';
|
|
73
|
+
/** Whether a PTY was requested but unavailable, so `spawn` was used instead. */
|
|
74
|
+
readonly ptyFellBack: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// file — read_file (pagination)
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
/** Input for the paginated `read_file` tool. */
|
|
82
|
+
export interface ReadFilePagedInput {
|
|
83
|
+
/** Absolute path to read. */
|
|
84
|
+
readonly path: string;
|
|
85
|
+
/** 0-based line offset to start from. Defaults to 0. */
|
|
86
|
+
readonly offset?: number;
|
|
87
|
+
/** Maximum number of lines to return. Omit for "to end of file". */
|
|
88
|
+
readonly limit?: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Result of a paginated read. */
|
|
92
|
+
export interface ReadFilePagedResult {
|
|
93
|
+
/** Absolute path that was read. */
|
|
94
|
+
readonly path: string;
|
|
95
|
+
/** The selected slice of lines (joined with `\n`). */
|
|
96
|
+
readonly content: string;
|
|
97
|
+
/** 0-based line offset the slice began at. */
|
|
98
|
+
readonly offset: number;
|
|
99
|
+
/** Number of lines returned. */
|
|
100
|
+
readonly lineCount: number;
|
|
101
|
+
/** Total number of lines in the file. */
|
|
102
|
+
readonly totalLines: number;
|
|
103
|
+
/** Whether more lines exist after the returned slice. */
|
|
104
|
+
readonly hasMore: boolean;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// file — apply_patch (fuzzy)
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
/** Input for the `apply_patch` tool (fuzzy, whitespace-tolerant replacement). */
|
|
112
|
+
export interface ApplyPatchInput {
|
|
113
|
+
/** Absolute path of the file to patch. */
|
|
114
|
+
readonly path: string;
|
|
115
|
+
/** Exact-or-fuzzy block of original text to locate. */
|
|
116
|
+
readonly oldText: string;
|
|
117
|
+
/** Replacement text. */
|
|
118
|
+
readonly newText: string;
|
|
119
|
+
/**
|
|
120
|
+
* Permit fuzzy (leading/trailing whitespace-insensitive) matching when an
|
|
121
|
+
* exact match is not found. Defaults to `true`.
|
|
122
|
+
*/
|
|
123
|
+
readonly fuzzy?: boolean;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Result of an `apply_patch`. */
|
|
127
|
+
export interface ApplyPatchResult {
|
|
128
|
+
/** Absolute path that was patched. */
|
|
129
|
+
readonly path: string;
|
|
130
|
+
/** Whether the replacement was applied. */
|
|
131
|
+
readonly applied: boolean;
|
|
132
|
+
/** How the match was located: exact, fuzzy (whitespace-normalised), or none. */
|
|
133
|
+
readonly matchKind: 'exact' | 'fuzzy' | 'none';
|
|
134
|
+
/** 0-based line where the replacement began (when applied). */
|
|
135
|
+
readonly startLine?: number;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// search — search_files (ripgrep)
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
/** Input for the ripgrep-backed `search_files` tool. */
|
|
143
|
+
export interface SearchFilesInput {
|
|
144
|
+
/** Pattern to search for (regex by default — see {@link SearchFilesInput.fixedStrings}). */
|
|
145
|
+
readonly pattern: string;
|
|
146
|
+
/** Root directory to search under. */
|
|
147
|
+
readonly root: string;
|
|
148
|
+
/** Treat {@link SearchFilesInput.pattern} as a literal string, not a regex. */
|
|
149
|
+
readonly fixedStrings?: boolean;
|
|
150
|
+
/** Case-insensitive matching. */
|
|
151
|
+
readonly ignoreCase?: boolean;
|
|
152
|
+
/** Restrict to files matching this ripgrep glob (e.g. `*.ts`). */
|
|
153
|
+
readonly glob?: string;
|
|
154
|
+
/** Cap on returned matches. Defaults to 1000. */
|
|
155
|
+
readonly maxResults?: number;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** A single `search_files` match. */
|
|
159
|
+
export interface SearchFilesMatch {
|
|
160
|
+
/** Absolute (or root-relative) path of the matching file. */
|
|
161
|
+
readonly path: string;
|
|
162
|
+
/** 1-based line number of the match. */
|
|
163
|
+
readonly line: number;
|
|
164
|
+
/** The matching line's text (trailing newline stripped). */
|
|
165
|
+
readonly text: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Result of `search_files`. */
|
|
169
|
+
export interface SearchFilesResult {
|
|
170
|
+
/** Matches in ripgrep order. */
|
|
171
|
+
readonly matches: readonly SearchFilesMatch[];
|
|
172
|
+
/** Whether {@link SearchFilesInput.maxResults} truncated the results. */
|
|
173
|
+
readonly truncated: boolean;
|
|
174
|
+
/**
|
|
175
|
+
* `true` when ripgrep (`rg`) was unavailable and the search degraded to a
|
|
176
|
+
* built-in scan, so callers can surface reduced fidelity.
|
|
177
|
+
*/
|
|
178
|
+
readonly degraded: boolean;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// git — status / diff / log / commit
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
|
|
185
|
+
/** Common options for the git tools. */
|
|
186
|
+
export interface GitToolBase {
|
|
187
|
+
/** Repository working directory. Defaults to `process.cwd()`. */
|
|
188
|
+
readonly cwd?: string;
|
|
189
|
+
/** Hard timeout in milliseconds. */
|
|
190
|
+
readonly timeoutMs?: number;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Input for `git_status`. */
|
|
194
|
+
export interface GitStatusInput extends GitToolBase {}
|
|
195
|
+
|
|
196
|
+
/** One porcelain-v1 status entry. */
|
|
197
|
+
export interface GitStatusEntry {
|
|
198
|
+
/** Two-char XY porcelain status code (e.g. ` M`, `A `, `??`). */
|
|
199
|
+
readonly status: string;
|
|
200
|
+
/** Path the status applies to. */
|
|
201
|
+
readonly path: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Result of `git_status`. */
|
|
205
|
+
export interface GitStatusResult {
|
|
206
|
+
/** The current branch name (`HEAD` when detached/unknown). */
|
|
207
|
+
readonly branch: string;
|
|
208
|
+
/** Parsed porcelain entries. */
|
|
209
|
+
readonly entries: readonly GitStatusEntry[];
|
|
210
|
+
/** Whether the working tree has any uncommitted changes. */
|
|
211
|
+
readonly clean: boolean;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Input for `git_diff`. */
|
|
215
|
+
export interface GitDiffInput extends GitToolBase {
|
|
216
|
+
/** Show staged (`--cached`) changes instead of the working tree. */
|
|
217
|
+
readonly staged?: boolean;
|
|
218
|
+
/** Restrict the diff to these paths. */
|
|
219
|
+
readonly paths?: readonly string[];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Result of `git_diff`. */
|
|
223
|
+
export interface GitDiffResult {
|
|
224
|
+
/** The unified diff text (empty when there are no changes). */
|
|
225
|
+
readonly diff: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/** Input for `git_log`. */
|
|
229
|
+
export interface GitLogInput extends GitToolBase {
|
|
230
|
+
/** Maximum number of commits to return. Defaults to 20. */
|
|
231
|
+
readonly maxCount?: number;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/** One commit in a `git_log` result. */
|
|
235
|
+
export interface GitLogEntry {
|
|
236
|
+
/** Full commit SHA. */
|
|
237
|
+
readonly sha: string;
|
|
238
|
+
/** Author name. */
|
|
239
|
+
readonly author: string;
|
|
240
|
+
/** ISO-8601 author date. */
|
|
241
|
+
readonly date: string;
|
|
242
|
+
/** Commit subject (first line). */
|
|
243
|
+
readonly subject: string;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Result of `git_log`. */
|
|
247
|
+
export interface GitLogResult {
|
|
248
|
+
/** Commits newest-first. */
|
|
249
|
+
readonly commits: readonly GitLogEntry[];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Input for `git_commit`. */
|
|
253
|
+
export interface GitCommitInput extends GitToolBase {
|
|
254
|
+
/** Commit message. */
|
|
255
|
+
readonly message: string;
|
|
256
|
+
/** Stage all tracked modifications first (`-a`). Defaults to `false`. */
|
|
257
|
+
readonly all?: boolean;
|
|
258
|
+
/** Explicit paths to stage before committing. */
|
|
259
|
+
readonly paths?: readonly string[];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Result of `git_commit`. */
|
|
263
|
+
export interface GitCommitResult {
|
|
264
|
+
/** Whether the commit was created. */
|
|
265
|
+
readonly committed: boolean;
|
|
266
|
+
/** The new commit SHA (when created). */
|
|
267
|
+
readonly sha?: string;
|
|
268
|
+
/** Git's stdout/stderr summary (e.g. "nothing to commit"). */
|
|
269
|
+
readonly summary: string;
|
|
270
|
+
}
|
package/src/tools/atomic.ts
CHANGED
|
@@ -36,6 +36,27 @@ export const TOOL_CLASSES = ['fs', 'shell', 'search', 'net', 'notebook'] as cons
|
|
|
36
36
|
/** One of the canonical {@link TOOL_CLASSES}. */
|
|
37
37
|
export type ToolClass = (typeof TOOL_CLASSES)[number];
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Agent-facing **toolset** groups (T1739 · AC4 · epic T11456).
|
|
41
|
+
*
|
|
42
|
+
* Where {@link TOOL_CLASSES} groups primitives by their SIDE-EFFECT surface (and
|
|
43
|
+
* therefore by guardrail policy), a {@link Toolset} groups tools by the
|
|
44
|
+
* AGENT-FACING CAPABILITY a model selects when reasoning — the dimension Hermes'
|
|
45
|
+
* `tools/registry.py` exposes to the loop. The two axes are orthogonal: an `fs`
|
|
46
|
+
* class primitive belongs to the `file` toolset, a `shell` class primitive to the
|
|
47
|
+
* `terminal` toolset, a `net` class primitive to the `web` toolset, etc.
|
|
48
|
+
*
|
|
49
|
+
* - `terminal` — shell / process execution (`executeShell`, `runGit`).
|
|
50
|
+
* - `file` — filesystem read/write/search (`readFileText`, `writeFileAtomic`, …).
|
|
51
|
+
* - `web` — outbound network / fetch (`fetch`).
|
|
52
|
+
* - `agent` — sub-agent / delegation / task orchestration tools.
|
|
53
|
+
* - `media` — image / audio / notebook authoring (`notebookEdit`, …).
|
|
54
|
+
*/
|
|
55
|
+
export const AGENT_TOOLSETS = ['terminal', 'file', 'web', 'agent', 'media'] as const;
|
|
56
|
+
|
|
57
|
+
/** One of the canonical {@link AGENT_TOOLSETS}. */
|
|
58
|
+
export type Toolset = (typeof AGENT_TOOLSETS)[number];
|
|
59
|
+
|
|
39
60
|
/**
|
|
40
61
|
* Descriptor for a single registered tool primitive. The registry of these is
|
|
41
62
|
* the SoT for "what atomic tools exist", consumed by the guardrail chokepoint
|
package/src/tools/index.ts
CHANGED
|
@@ -7,6 +7,30 @@
|
|
|
7
7
|
* @epic T9835
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
// === Agent-facing tool families (T1741 / T11456) ===
|
|
11
|
+
export type {
|
|
12
|
+
ApplyPatchInput,
|
|
13
|
+
ApplyPatchResult,
|
|
14
|
+
GitCommitInput,
|
|
15
|
+
GitCommitResult,
|
|
16
|
+
GitDiffInput,
|
|
17
|
+
GitDiffResult,
|
|
18
|
+
GitLogEntry,
|
|
19
|
+
GitLogInput,
|
|
20
|
+
GitLogResult,
|
|
21
|
+
GitStatusEntry,
|
|
22
|
+
GitStatusInput,
|
|
23
|
+
GitStatusResult,
|
|
24
|
+
GitToolBase,
|
|
25
|
+
ReadFilePagedInput,
|
|
26
|
+
ReadFilePagedResult,
|
|
27
|
+
RunShellInput,
|
|
28
|
+
RunShellResult,
|
|
29
|
+
SearchFilesInput,
|
|
30
|
+
SearchFilesMatch,
|
|
31
|
+
SearchFilesResult,
|
|
32
|
+
ShellRunMode,
|
|
33
|
+
} from './agent-tools.js';
|
|
10
34
|
export type { FetchBrainEntriesInput, FetchBrainEntriesOutput } from './brain-fetch.js';
|
|
11
35
|
export type { ObserveBrainInput, ObserveBrainOutput } from './brain-observe.js';
|
|
12
36
|
// === BrainTools (T10070 / T9835c) ===
|
|
@@ -41,3 +65,25 @@ export type {
|
|
|
41
65
|
ScoreTaskInput,
|
|
42
66
|
ScoreTaskResult,
|
|
43
67
|
} from './score-task-priority.js';
|
|
68
|
+
// === Web + browser agent tools (T1742 / T11456) ===
|
|
69
|
+
export type {
|
|
70
|
+
AccessibilityNode,
|
|
71
|
+
BrowserActionResult,
|
|
72
|
+
BrowserClickInput,
|
|
73
|
+
BrowserNavigateInput,
|
|
74
|
+
BrowserPageState,
|
|
75
|
+
BrowserPressInput,
|
|
76
|
+
BrowserScrollDirection,
|
|
77
|
+
BrowserScrollInput,
|
|
78
|
+
BrowserScrollResult,
|
|
79
|
+
BrowserSnapshotResult,
|
|
80
|
+
BrowserTypeInput,
|
|
81
|
+
BrowserVisionInput,
|
|
82
|
+
BrowserVisionResult,
|
|
83
|
+
WebExtractInput,
|
|
84
|
+
WebExtractResult,
|
|
85
|
+
WebSearchBackendId,
|
|
86
|
+
WebSearchHit,
|
|
87
|
+
WebSearchInput,
|
|
88
|
+
WebSearchResult,
|
|
89
|
+
} from './web-tools.js';
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
* @see ./atomic.js — the tool I/O shapes this seam composes over
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
|
+
import type { RunShellInput, RunShellResult } from './agent-tools.js';
|
|
47
48
|
import type {
|
|
48
49
|
ExecuteShellInput,
|
|
49
50
|
ExecuteShellResult,
|
|
@@ -86,6 +87,12 @@ export interface GuardedToolSurface {
|
|
|
86
87
|
pathExists(input: PathExistsInput): Promise<PathExistsResult>;
|
|
87
88
|
/** Run a command with explicit cwd/env/timeout through the guard. */
|
|
88
89
|
executeShell(input: ExecuteShellInput): Promise<ExecuteShellResult>;
|
|
90
|
+
/**
|
|
91
|
+
* Run a command under a pseudo-terminal (PTY) through the guard, falling back
|
|
92
|
+
* to a non-PTY spawn when a PTY backend is unavailable. Subject to the same
|
|
93
|
+
* deny-first command policy + env scrubbing as {@link GuardedToolSurface.executeShell}.
|
|
94
|
+
*/
|
|
95
|
+
executePty(input: RunShellInput): Promise<RunShellResult>;
|
|
89
96
|
/** Run a git subcommand through the guard. */
|
|
90
97
|
runGit(input: RunGitInput): Promise<ExecuteShellResult>;
|
|
91
98
|
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web + browser agent-tool I/O contracts (T1742 · epic T11456 · SG-TOOLS).
|
|
3
|
+
*
|
|
4
|
+
* The shared, types-only I/O shapes for the `web` toolset surfaced through the
|
|
5
|
+
* `AgentToolRegistry` (`packages/core/src/tools/agent-registry.ts`), on top of
|
|
6
|
+
* the terminal/file/search/git families ({@link ./agent-tools.js}):
|
|
7
|
+
*
|
|
8
|
+
* - **web_search** — pluggable, backend-agnostic web search
|
|
9
|
+
* ({@link WebSearchInput} / {@link WebSearchResult}). NO hard paid-API dep:
|
|
10
|
+
* a backend is resolved at call time and the tool degrades gracefully to an
|
|
11
|
+
* `unavailable` result when none is configured.
|
|
12
|
+
* - **web_extract** — fetch a URL and convert its HTML body to markdown
|
|
13
|
+
* ({@link WebExtractInput} / {@link WebExtractResult}).
|
|
14
|
+
* - **browser_*** — Playwright-driven browser automation
|
|
15
|
+
* ({@link BrowserNavigateInput} … {@link BrowserVisionResult}). Playwright is
|
|
16
|
+
* an OPTIONAL, lazily-loaded dependency — these tools' `available()` predicate
|
|
17
|
+
* returns `false` (with an install hint) when it is absent.
|
|
18
|
+
*
|
|
19
|
+
* The web tools compose over the `net` side-effect surface; the browser tools
|
|
20
|
+
* over a Playwright-managed `shell`-class process. Like every agent tool, their
|
|
21
|
+
* executables perform side effects through the injected `GuardedToolSurface` (or,
|
|
22
|
+
* for the AI call in {@link BrowserVisionResult}, through the E9
|
|
23
|
+
* `resolveLLMForSystem` chokepoint) — never a raw provider/network bypass.
|
|
24
|
+
* Types-only — no runtime logic (Gate 10 `contracts-purity`).
|
|
25
|
+
*
|
|
26
|
+
* @epic T11456
|
|
27
|
+
* @task T1742
|
|
28
|
+
* @see ./agent-tools.js — the terminal/file/search/git family I/O shapes
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// web_search — pluggable, backend-agnostic
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Identifier of a {@link WebSearchInput} backend.
|
|
37
|
+
*
|
|
38
|
+
* - `duckduckgo` — DuckDuckGo's keyless HTML endpoint (no API key required).
|
|
39
|
+
* - `searxng` — a self-hosted / public SearXNG JSON instance (URL via config/env).
|
|
40
|
+
* - `auto` — try each configured backend in priority order, first success wins.
|
|
41
|
+
*
|
|
42
|
+
* NONE require a paid API key; the set is open by design so a deployment can
|
|
43
|
+
* register its own backend. The string union here is the canonical builtin set.
|
|
44
|
+
*/
|
|
45
|
+
export type WebSearchBackendId = 'duckduckgo' | 'searxng' | 'auto';
|
|
46
|
+
|
|
47
|
+
/** Input for the `web_search` tool. */
|
|
48
|
+
export interface WebSearchInput {
|
|
49
|
+
/** Free-text search query. */
|
|
50
|
+
readonly query: string;
|
|
51
|
+
/** Maximum number of results to return. Defaults to 10. */
|
|
52
|
+
readonly maxResults?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Preferred backend. Defaults to `auto` — the first configured/reachable
|
|
55
|
+
* backend answers. An explicit id pins a single backend.
|
|
56
|
+
*/
|
|
57
|
+
readonly backend?: WebSearchBackendId;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** A single web-search hit. */
|
|
61
|
+
export interface WebSearchHit {
|
|
62
|
+
/** Result title. */
|
|
63
|
+
readonly title: string;
|
|
64
|
+
/** Absolute result URL. */
|
|
65
|
+
readonly url: string;
|
|
66
|
+
/** Snippet / description (may be empty). */
|
|
67
|
+
readonly snippet: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Result of `web_search`. */
|
|
71
|
+
export interface WebSearchResult {
|
|
72
|
+
/** The originating query (echoed for traceability). */
|
|
73
|
+
readonly query: string;
|
|
74
|
+
/** Hits in backend-ranked order (empty when none / unavailable). */
|
|
75
|
+
readonly results: readonly WebSearchHit[];
|
|
76
|
+
/** The backend that actually answered, or `null` when none was available. */
|
|
77
|
+
readonly backend: WebSearchBackendId | null;
|
|
78
|
+
/**
|
|
79
|
+
* `true` when NO backend could answer (none configured, network egress
|
|
80
|
+
* denied, or every backend failed). Callers MUST treat this as a soft
|
|
81
|
+
* "no search capability" signal — it is NOT an error.
|
|
82
|
+
*/
|
|
83
|
+
readonly unavailable: boolean;
|
|
84
|
+
/** Human-readable reason when {@link WebSearchResult.unavailable} is `true`. */
|
|
85
|
+
readonly reason?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// web_extract — URL → markdown
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
|
|
92
|
+
/** Input for the `web_extract` tool. */
|
|
93
|
+
export interface WebExtractInput {
|
|
94
|
+
/** Absolute URL to fetch and convert. */
|
|
95
|
+
readonly url: string;
|
|
96
|
+
/** Hard timeout in milliseconds. Defaults to 30000. */
|
|
97
|
+
readonly timeoutMs?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Cap on the markdown length (characters). Output beyond this is truncated
|
|
100
|
+
* and {@link WebExtractResult.truncated} set. Defaults to 100000.
|
|
101
|
+
*/
|
|
102
|
+
readonly maxChars?: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Result of `web_extract`. */
|
|
106
|
+
export interface WebExtractResult {
|
|
107
|
+
/** The fetched URL. */
|
|
108
|
+
readonly url: string;
|
|
109
|
+
/** HTTP status code of the fetch. */
|
|
110
|
+
readonly status: number;
|
|
111
|
+
/** Document `<title>`, when present. */
|
|
112
|
+
readonly title: string;
|
|
113
|
+
/** The page body converted to markdown. */
|
|
114
|
+
readonly markdown: string;
|
|
115
|
+
/** Whether {@link WebExtractInput.maxChars} truncated the markdown. */
|
|
116
|
+
readonly truncated: boolean;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
// browser_* — Playwright-driven automation
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
/** Input for `browser_navigate`. */
|
|
124
|
+
export interface BrowserNavigateInput {
|
|
125
|
+
/** Absolute URL to navigate the browser to. */
|
|
126
|
+
readonly url: string;
|
|
127
|
+
/**
|
|
128
|
+
* When to consider navigation complete. Defaults to `load`.
|
|
129
|
+
* Mirrors Playwright's `waitUntil` states.
|
|
130
|
+
*/
|
|
131
|
+
readonly waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';
|
|
132
|
+
/** Per-navigation timeout in milliseconds. Defaults to 30000. */
|
|
133
|
+
readonly timeoutMs?: number;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Result common to navigation / interaction browser tools. */
|
|
137
|
+
export interface BrowserPageState {
|
|
138
|
+
/** The page's current URL after the operation. */
|
|
139
|
+
readonly url: string;
|
|
140
|
+
/** The page's `document.title` after the operation. */
|
|
141
|
+
readonly title: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Input for `browser_click`. */
|
|
145
|
+
export interface BrowserClickInput {
|
|
146
|
+
/** A CSS / Playwright selector for the element to click. */
|
|
147
|
+
readonly selector: string;
|
|
148
|
+
/** Per-action timeout in milliseconds. Defaults to 15000. */
|
|
149
|
+
readonly timeoutMs?: number;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Input for `browser_type`. */
|
|
153
|
+
export interface BrowserTypeInput {
|
|
154
|
+
/** A CSS / Playwright selector for the input element. */
|
|
155
|
+
readonly selector: string;
|
|
156
|
+
/** The text to type into the element. */
|
|
157
|
+
readonly text: string;
|
|
158
|
+
/** Clear the field before typing. Defaults to `true`. */
|
|
159
|
+
readonly clear?: boolean;
|
|
160
|
+
/** Per-action timeout in milliseconds. Defaults to 15000. */
|
|
161
|
+
readonly timeoutMs?: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Input for `browser_press` (a single key / chord). */
|
|
165
|
+
export interface BrowserPressInput {
|
|
166
|
+
/**
|
|
167
|
+
* The key (or `Modifier+Key` chord) to press, in Playwright key syntax
|
|
168
|
+
* (e.g. `Enter`, `Tab`, `Control+A`, `ArrowDown`).
|
|
169
|
+
*/
|
|
170
|
+
readonly key: string;
|
|
171
|
+
/** Optional selector to focus before pressing. */
|
|
172
|
+
readonly selector?: string;
|
|
173
|
+
/** Per-action timeout in milliseconds. Defaults to 15000. */
|
|
174
|
+
readonly timeoutMs?: number;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Result of a `browser_click` / `browser_type` / `browser_press` action. */
|
|
178
|
+
export interface BrowserActionResult extends BrowserPageState {
|
|
179
|
+
/** The action that was performed. */
|
|
180
|
+
readonly action: 'click' | 'type' | 'press';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** A single node in the {@link BrowserSnapshotResult} accessibility tree. */
|
|
184
|
+
export interface AccessibilityNode {
|
|
185
|
+
/** ARIA role (e.g. `button`, `link`, `textbox`). */
|
|
186
|
+
readonly role: string;
|
|
187
|
+
/** Accessible name, when present. */
|
|
188
|
+
readonly name?: string;
|
|
189
|
+
/** Current value (form controls). */
|
|
190
|
+
readonly value?: string;
|
|
191
|
+
/** Child nodes (depth-first). */
|
|
192
|
+
readonly children?: readonly AccessibilityNode[];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Result of `browser_snapshot` — the page accessibility tree. */
|
|
196
|
+
export interface BrowserSnapshotResult extends BrowserPageState {
|
|
197
|
+
/** The root of the accessibility tree, or `null` when none is available. */
|
|
198
|
+
readonly tree: AccessibilityNode | null;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Scroll direction for `browser_scroll`. */
|
|
202
|
+
export type BrowserScrollDirection = 'up' | 'down';
|
|
203
|
+
|
|
204
|
+
/** Input for `browser_scroll`. */
|
|
205
|
+
export interface BrowserScrollInput {
|
|
206
|
+
/** Direction to scroll. */
|
|
207
|
+
readonly direction: BrowserScrollDirection;
|
|
208
|
+
/**
|
|
209
|
+
* Pixels to scroll by. Defaults to roughly one viewport height (800px).
|
|
210
|
+
*/
|
|
211
|
+
readonly amountPx?: number;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Result of `browser_scroll`. */
|
|
215
|
+
export interface BrowserScrollResult extends BrowserPageState {
|
|
216
|
+
/** The direction that was scrolled. */
|
|
217
|
+
readonly direction: BrowserScrollDirection;
|
|
218
|
+
/** The vertical scroll position (pixels from top) after scrolling. */
|
|
219
|
+
readonly scrollY: number;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Input for `browser_vision` (screenshot + AI analysis). */
|
|
223
|
+
export interface BrowserVisionInput {
|
|
224
|
+
/**
|
|
225
|
+
* The question / instruction the vision model should answer about the current
|
|
226
|
+
* page screenshot (e.g. "What is the primary call-to-action on this page?").
|
|
227
|
+
*/
|
|
228
|
+
readonly prompt: string;
|
|
229
|
+
/** Capture the full scrollable page rather than just the viewport. Defaults to `false`. */
|
|
230
|
+
readonly fullPage?: boolean;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Result of `browser_vision`. */
|
|
234
|
+
export interface BrowserVisionResult extends BrowserPageState {
|
|
235
|
+
/**
|
|
236
|
+
* The vision model's textual analysis of the screenshot, or `null` when no
|
|
237
|
+
* LLM credential was reachable (graceful degradation — NOT an error).
|
|
238
|
+
*/
|
|
239
|
+
readonly analysis: string | null;
|
|
240
|
+
/** The model id that produced {@link BrowserVisionResult.analysis}, when available. */
|
|
241
|
+
readonly model?: string;
|
|
242
|
+
/**
|
|
243
|
+
* `true` when the AI call was skipped because no LLM credential resolved
|
|
244
|
+
* through the E9 chokepoint. The screenshot was still captured.
|
|
245
|
+
*/
|
|
246
|
+
readonly aiUnavailable: boolean;
|
|
247
|
+
}
|