dsh-agy-cli 0.0.0-stage → 0.12.1

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.
Files changed (91) hide show
  1. package/LICENSE +31 -0
  2. package/README.en.md +48 -0
  3. package/README.md +67 -2
  4. package/agents/dsh-agy-image-view.md +17 -0
  5. package/agents/dsh-agy-mcp-executor.md +32 -0
  6. package/agents/dsh-agy-read-only.md +20 -0
  7. package/agents/dsh-agy-tool-free.md +16 -0
  8. package/agents/dsh-agy-workspace-write.md +23 -0
  9. package/bin/dsh-agy-cli.js +9 -0
  10. package/bin/win32-x64/agy-launcher.exe +0 -0
  11. package/cordis.patch.yml +16 -0
  12. package/dist/client.js +4259 -0
  13. package/lib/agent-installer.d.ts +66 -0
  14. package/lib/agent-installer.js +147 -0
  15. package/lib/agent-presets.d.ts +42 -0
  16. package/lib/agent-presets.js +130 -0
  17. package/lib/agents-cli.d.ts +3 -0
  18. package/lib/agents-cli.js +110 -0
  19. package/lib/agy/diagnostics.d.ts +29 -0
  20. package/lib/agy/diagnostics.js +109 -0
  21. package/lib/agy/errors.d.ts +20 -0
  22. package/lib/agy/errors.js +77 -0
  23. package/lib/agy/experimental-transport.d.ts +79 -0
  24. package/lib/agy/experimental-transport.js +612 -0
  25. package/lib/agy/keepalive.d.ts +140 -0
  26. package/lib/agy/keepalive.js +445 -0
  27. package/lib/agy/limiter.d.ts +32 -0
  28. package/lib/agy/limiter.js +111 -0
  29. package/lib/agy/log.d.ts +214 -0
  30. package/lib/agy/log.js +503 -0
  31. package/lib/agy/models.d.ts +49 -0
  32. package/lib/agy/models.js +203 -0
  33. package/lib/agy/overrides.d.ts +17 -0
  34. package/lib/agy/overrides.js +73 -0
  35. package/lib/agy/parser.d.ts +102 -0
  36. package/lib/agy/parser.js +492 -0
  37. package/lib/agy/persistent-transport.d.ts +101 -0
  38. package/lib/agy/persistent-transport.js +753 -0
  39. package/lib/agy/process.d.ts +144 -0
  40. package/lib/agy/process.js +452 -0
  41. package/lib/agy/redact.d.ts +3 -0
  42. package/lib/agy/redact.js +24 -0
  43. package/lib/agy/stream-protocol.d.ts +50 -0
  44. package/lib/agy/stream-protocol.js +156 -0
  45. package/lib/agy/windows-launcher.d.ts +21 -0
  46. package/lib/agy/windows-launcher.js +76 -0
  47. package/lib/diagnostics.d.ts +78 -0
  48. package/lib/diagnostics.js +162 -0
  49. package/lib/doctor.d.ts +138 -0
  50. package/lib/doctor.js +940 -0
  51. package/lib/dsh/context.d.ts +133 -0
  52. package/lib/dsh/context.js +352 -0
  53. package/lib/dsh-home.d.ts +6 -0
  54. package/lib/dsh-home.js +11 -0
  55. package/lib/index.d.ts +54 -0
  56. package/lib/index.js +267 -0
  57. package/lib/mcp/agy-registration.d.ts +70 -0
  58. package/lib/mcp/agy-registration.js +245 -0
  59. package/lib/mcp/bridge.d.ts +73 -0
  60. package/lib/mcp/bridge.js +295 -0
  61. package/lib/mcp/endpoint.d.ts +41 -0
  62. package/lib/mcp/endpoint.js +142 -0
  63. package/lib/mcp/protocol.d.ts +107 -0
  64. package/lib/mcp/protocol.js +197 -0
  65. package/lib/mcp/tool-projection.d.ts +64 -0
  66. package/lib/mcp/tool-projection.js +168 -0
  67. package/lib/provider/agy.d.ts +153 -0
  68. package/lib/provider/agy.js +2159 -0
  69. package/lib/provider/config.d.ts +226 -0
  70. package/lib/provider/config.js +294 -0
  71. package/lib/provider/error-codes.d.ts +22 -0
  72. package/lib/provider/error-codes.js +29 -0
  73. package/lib/provider/image-bridge.d.ts +60 -0
  74. package/lib/provider/image-bridge.js +290 -0
  75. package/lib/provider/mock.d.ts +15 -0
  76. package/lib/provider/mock.js +78 -0
  77. package/lib/provider/prompt-budget.d.ts +45 -0
  78. package/lib/provider/prompt-budget.js +596 -0
  79. package/lib/provider/serialize.d.ts +15 -0
  80. package/lib/provider/serialize.js +82 -0
  81. package/lib/provider/tool-protocol.d.ts +80 -0
  82. package/lib/provider/tool-protocol.js +848 -0
  83. package/lib/provider/tool-schema-file.d.ts +11 -0
  84. package/lib/provider/tool-schema-file.js +27 -0
  85. package/lib/session/file-store.d.ts +56 -0
  86. package/lib/session/file-store.js +186 -0
  87. package/lib/session/store.d.ts +49 -0
  88. package/lib/session/store.js +62 -0
  89. package/lib/web/router.d.ts +19 -0
  90. package/lib/web/router.js +994 -0
  91. package/package.json +115 -4
@@ -0,0 +1,226 @@
1
+ import z from '@deepseek-ai/schemastery';
2
+ import { type AgentPresetId } from '../agent-presets.js';
3
+ export interface Config {
4
+ /** Keep the bundle inert until explicitly enabled. */
5
+ enabled?: boolean;
6
+ /** DSH provider route owned by this plugin. */
7
+ provider?: string;
8
+ /** AGY model passed to the CLI when a request does not override it. */
9
+ model?: string;
10
+ /** Explicit model catalog; legacy `model` remains the default/fallback entry. */
11
+ models?: ModelConfig[];
12
+ /** Visible models filter; empty means show all discovered models. */
13
+ visibleModels?: string[];
14
+ /** Discover additional models with `agy models`; `off` keeps static-only behavior. */
15
+ modelDiscovery?: 'auto' | 'off';
16
+ /** In-memory model discovery cache lifetime. */
17
+ modelDiscoveryTtlMs?: number;
18
+ /** Timeout for the quota-free `agy models` command. */
19
+ modelDiscoveryTimeoutMs?: number;
20
+ /** Ownership policy for DSH tool schemas; AGY remains the internal tool owner. */
21
+ toolPolicy?: ToolPolicy;
22
+ /**
23
+ * Expose DSH tools to AGY over MCP instead of serializing their schemas into
24
+ * the prompt. The MCP path keeps the whole prompt budget for conversation
25
+ * history, returns tool calls as real AGY tool events (so the intermediate
26
+ * steps stay visible in the DSH transcript), and routes every execution
27
+ * through the host tool pipeline. Requires the host `webServer` and `tools`
28
+ * services; when either is missing the provider falls back to the prompt
29
+ * contract so the route keeps working.
30
+ */
31
+ mcpBridge?: boolean;
32
+ /** Restrict the MCP tool projection to these DSH tool names; empty exposes all. */
33
+ mcpToolAllowlist?: string[];
34
+ /** AGY agent profile; must name a template installed under AGY's `agents/` directory. */
35
+ agent?: string;
36
+ /** Optional bundled Agent capability profile; omitted preserves the configured agent. */
37
+ agentPreset?: AgentPresetId;
38
+ /** @deprecated Use DSH session workspace; kept for legacy agy-owned compatibility. */
39
+ workspaceRoot?: string;
40
+ /** Explicit AGY executable path; empty means discover from environment/PATH. */
41
+ agyPath?: string;
42
+ /**
43
+ * Backstop for one AGY child process: the ceiling on total wall time. Only a
44
+ * process whose output *never stops* can reach it, because the idle watchdog
45
+ * below decides every normal case. Omitted means no ceiling.
46
+ */
47
+ timeoutMs?: number;
48
+ /**
49
+ * Inactivity budget for one AGY child process: killed when no stdout/stderr
50
+ * line arrives for this long. Re-armed on every line, so a long reasoning
51
+ * step or a long tool chain is never mistaken for a hang — this is the
52
+ * instrument that actually fires. MUST stay below `timeoutMs`: both timers are
53
+ * armed inside the same process, so a wall clock that expires first makes
54
+ * this watchdog unreachable and every healthy long turn dies as `timeout`.
55
+ */
56
+ idleTimeoutMs?: number;
57
+ /**
58
+ * How the request pipe is retired after AGY's user frame is written. `hold`
59
+ * (default) keeps it open until AGY emits its closing `result` line, because
60
+ * an immediate EOF is read as "no next turn": AGY shuts its store manager
61
+ * down and cancels the turn it is still generating, which reaches the user as
62
+ * text that appears and is then rolled back. `close` restores the historical
63
+ * behaviour for callers that need the process to exit on EOF.
64
+ */
65
+ stdinMode?: 'hold' | 'close';
66
+ /** `full` sends DSH history; `resume` reuses an AGY conversation. */
67
+ sessionMode?: 'resume' | 'full';
68
+ /**
69
+ * Where the durable `DSH sessionId -> AGY conversationId` map lives, so
70
+ * `sessionMode: resume` survives a host restart. Empty uses
71
+ * `<DSH_HOME>/agy-cli/sessions.json`. A value ending in `.json` is a
72
+ * file; anything else is a directory holding `sessions.json`.
73
+ */
74
+ sessionStorePath?: string;
75
+ /** Minimum AGY version accepted by the diagnostic command. */
76
+ minimumAgyVersion?: string;
77
+ /** Maximum number of active AGY child processes per adapter instance. */
78
+ maxConcurrent?: number;
79
+ /** Maximum number of AGY requests waiting for a process slot. */
80
+ maxQueue?: number;
81
+ /** Maximum queue wait in milliseconds; `0` disables the queue timeout. */
82
+ queueTimeoutMs?: number;
83
+ /** Maximum stdout/stderr bytes captured from one AGY process. */
84
+ maxOutputBytes?: number;
85
+ /** Maximum length of one AGY stream-json line. */
86
+ maxEventLineLength?: number;
87
+ /** Maximum UTF-8 bytes allowed for one encoded AGY stream-json input frame. */
88
+ inputFrameLimitBytes?: number;
89
+ /** Maximum UTF-8 bytes retained for one serialized DSH tool result. */
90
+ maxSingleToolResultBytes?: number;
91
+ /** Maximum UTF-8 bytes retained across serialized historical DSH tool results. */
92
+ maxHistoricalToolResultBytes?: number;
93
+ /** Number of one-shot JSON-format repair attempts for DSH-owned tools. */
94
+ toolProtocolRepairRetries?: number;
95
+ /** Safe final-message fallback after a failed JSON repair. */
96
+ toolProtocolPlainTextFallback?: 'off' | 'final-message';
97
+ /** Provider-owned bounded retry policy; omission follows DSH normal defaults. */
98
+ retryPolicy?: AgyRetryPolicyConfig;
99
+ /** Optional model/Agent/effort overrides for DSH auxiliary call purposes. */
100
+ purposeRoutes?: PurposeRoutesConfig;
101
+ /** Transport for AGY requests; 'one-shot' keeps 0.7.0 behavior, 'persistent' opt-in reuses one AGY stream-json worker per DSH session. */
102
+ transport?: TransportMode;
103
+ /** Idle TTL for a persistent worker in ms; 0 closes immediately after a turn. */
104
+ persistentIdleTtlMs?: number;
105
+ /** Ready timeout for persistent worker startup in ms. */
106
+ persistentReadyTimeoutMs?: number;
107
+ /** Fallback policy when persistent cannot start: never or before-accept only. */
108
+ persistentFallback?: PersistentFallbackMode;
109
+ /**
110
+ * How often the plugin checks AGY's keyring token, in ms; `0` disables the
111
+ * check. The check is a Credential Manager read, and starting agy.exe only
112
+ * happens on the tick inside `tokenKeepaliveLeadMs` before the expiry — AGY
113
+ * ignores a token it still considers valid, so a wide window would just spin
114
+ * the process for nothing. Keep this well under the lead: 60 s interval with a
115
+ * 60 s lead gives several chances to fire before the credential dies.
116
+ */
117
+ tokenKeepaliveMs?: number;
118
+ /**
119
+ * The token is renewed once it has less life than this. AGY itself only
120
+ * rotates an EXPIRED token, so this is really "fire on the last tick before
121
+ * the moment it lapses" — see `src/agy/keepalive.ts`.
122
+ */
123
+ tokenKeepaliveLeadMs?: number;
124
+ /**
125
+ * Working directory handed to the renewal run. agy itself only reads the
126
+ * keyring/network during a wake-up turn, so any existing directory works; the
127
+ * plugin cannot assume the host process has a usable one, and the host's cwd
128
+ * is not guaranteed to exist (a removed workspace directory makes Node's
129
+ * spawn fail with a bare ENOENT that reads like a missing executable).
130
+ * Defaults to the user profile directory.
131
+ */
132
+ tokenKeepaliveCwd?: string;
133
+ /** AttachmentStore-to-AGY image bridge; omitted/off preserves text-only behavior. */
134
+ imageInput?: 'off' | 'experimental';
135
+ /** Deterministic response used only by the M1 mock route. */
136
+ response?: string;
137
+ /** Optional delay used only by the M1 mock route. */
138
+ delayMs?: number;
139
+ }
140
+ export type ToolPolicy = 'reject' | 'agy-owned' | 'dsh-owned';
141
+ export type TransportMode = 'one-shot' | 'persistent';
142
+ export type PersistentFallbackMode = 'never' | 'before-accept';
143
+ export declare const AGY_RETRYABLE_CODES: readonly ["EMPTY_RESPONSE", "RATE_LIMIT", "SERVER", "TIMEOUT", "TRANSPORT", "AGY_INPUT_FAILED", "AGY_SPAWN_FAILED"];
144
+ export type AgyRetryableCode = typeof AGY_RETRYABLE_CODES[number];
145
+ export interface AgyRetryPolicyConfig {
146
+ /** Eligible retries after the first AGY process; hard capped at DSH's default of 5. */
147
+ maxRetries?: number;
148
+ /** Stable transient codes allowed to consume another AGY attempt. */
149
+ retryableCodes?: AgyRetryableCode[];
150
+ }
151
+ export type AgyReasoningEffortConfig = 'low' | 'medium' | 'high';
152
+ export interface PurposeRouteConfig {
153
+ /** Optional model override for this auxiliary call purpose. */
154
+ model?: string;
155
+ /** Optional AGY Agent override for this auxiliary call purpose. */
156
+ agent?: string;
157
+ /** Optional AGY reasoning effort override for this auxiliary call purpose. */
158
+ reasoningEffort?: AgyReasoningEffortConfig;
159
+ }
160
+ export interface PurposeRoutesConfig {
161
+ compaction?: PurposeRouteConfig;
162
+ sessionTitle?: PurposeRouteConfig;
163
+ }
164
+ export interface ModelConfig {
165
+ /** Exact model id passed to AGY. */
166
+ id: string;
167
+ /** Optional selector label; defaults to `id`. */
168
+ name?: string;
169
+ /** Optional selector description. */
170
+ description?: string;
171
+ /** Optional provider-declared combined context capacity. */
172
+ contextWindow?: number;
173
+ }
174
+ export declare const DEFAULT_MODEL = "gemini-3.1-pro";
175
+ /**
176
+ * The AGY agent profile used when the config does not name one.
177
+ *
178
+ * This must be a template that ships with this package and is installed under
179
+ * AGY's `agents/` directory: AGY rejects an unknown profile outright, before it
180
+ * accepts any input, with `exit 1` and
181
+ * `error: unknown agent "<name>" (available: ...)`. The host sees that as an
182
+ * early process death and reports it as a stdin failure, so a name that is not
183
+ * installable turns into a misleading error far from the cause.
184
+ *
185
+ * It used to be `deepseek-proxy`, an agent that exists only in the upstream
186
+ * author's own environment; every fresh install therefore failed out of the box.
187
+ */
188
+ export declare const DEFAULT_AGENT = "dsh-agy-mcp-executor";
189
+ export declare function createConfigSchema(defaults?: {
190
+ enabled?: boolean;
191
+ toolPolicy?: ToolPolicy;
192
+ }): z<Config>;
193
+ /** Programmatic library default: enabled=false, toolPolicy=reject */
194
+ export declare const Config: z<Config>;
195
+ /** Bundle default for DSH profile plugin add: enabled=true, DSH owns tools. */
196
+ export declare const BundleConfig: z<Config>;
197
+ /**
198
+ * Resolve the effective catalog while keeping the 0.1.0 `model` setting
199
+ * compatible. Catalog membership is advisory; unknown exact model ids remain
200
+ * valid request targets and are handled by each adapter's resolveModel().
201
+ */
202
+ export declare function configuredModels(config?: Pick<Config, 'model' | 'models'>): readonly ModelConfig[];
203
+ /**
204
+ * Read a boolean config field that may have been projected as a volatile live
205
+ * reference.
206
+ *
207
+ * `enabled` carries `.volatile()` so the host's SettingsForms can project this
208
+ * Config into the `dsh-agy-cli` settings namespace — without at least one
209
+ * volatile field the Models page does not render our row at all. The cost is
210
+ * that the host hands the plugin a *reference* object (`{ get() }`, written
211
+ * through a symbol key) instead of the plain boolean the profile declares, so
212
+ * `config.enabled === true` is false no matter what the user configured.
213
+ *
214
+ * That comparison used to gate `apply()`: the directory and the HTTP routes
215
+ * were registered (they run before the gate) while the provider adapter never
216
+ * was, i.e. the plugin was half-mounted and `/plugins/agy-cli/status` reported
217
+ * `enabled: {}`. Read the flag through here instead of comparing directly.
218
+ */
219
+ export declare function readConfigFlag(value: unknown): boolean;
220
+ /** Normalize a possibly suffixed model id to its base (strip -low/-medium/-high). */
221
+ export declare function normalizeModelId(id: string): string;
222
+ /** Extract effort suffix from a model id, if present. */
223
+ export declare function extractModelEffort(id: string): 'low' | 'medium' | 'high' | undefined;
224
+ /** Filter catalog by visibleModels (empty = all). */
225
+ export declare function filterVisibleModels(models: readonly ModelConfig[], visibleModels: readonly string[] | undefined): readonly ModelConfig[];
226
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,294 @@
1
+ import z from '@deepseek-ai/schemastery';
2
+ import { AGENT_PRESET_IDS } from '../agent-presets.js';
3
+ import { DEFAULT_INPUT_FRAME_LIMIT_BYTES, DEFAULT_MAX_HISTORICAL_TOOL_RESULT_BYTES, DEFAULT_MAX_SINGLE_TOOL_RESULT_BYTES, } from './prompt-budget.js';
4
+ // Keep the default route policy aligned with @deepseek-ai/dsh-llm.
5
+ // The DSH retry executor owns the retry loop; this list only declares which
6
+ // stable provider failures are eligible for that executor.
7
+ //
8
+ // AGY_INPUT_FAILED and AGY_SPAWN_FAILED are transient on this host: the AGY
9
+ // binary runs its own eligibility check (loadCodeAssist) against Google before
10
+ // it accepts any stream-json input, and that call is intermittently reset when
11
+ // it goes through the local HTTP proxy. AGY then exits 1-2s after start, so our
12
+ // write to the child's stdin lands on a closed pipe and surfaces as "Unable to
13
+ // write AGY stream-json input (Error:EOF stage=stdin)" — observed verbatim at
14
+ // 2026-10-13 15:02 and reproduced with an 184 KB frame. Nothing about the
15
+ // request is wrong, so one more attempt genuinely fixes it. AGY_INPUT_TOO_LARGE
16
+ // is deliberately absent: a frame above the configured limit never shrinks on
17
+ // its own, and retrying it only burns quota.
18
+ export const AGY_RETRYABLE_CODES = [
19
+ 'EMPTY_RESPONSE',
20
+ 'RATE_LIMIT',
21
+ 'SERVER',
22
+ 'TIMEOUT',
23
+ 'TRANSPORT',
24
+ 'AGY_INPUT_FAILED',
25
+ 'AGY_SPAWN_FAILED',
26
+ ];
27
+ export const DEFAULT_MODEL = 'gemini-3.1-pro';
28
+ /**
29
+ * The AGY agent profile used when the config does not name one.
30
+ *
31
+ * This must be a template that ships with this package and is installed under
32
+ * AGY's `agents/` directory: AGY rejects an unknown profile outright, before it
33
+ * accepts any input, with `exit 1` and
34
+ * `error: unknown agent "<name>" (available: ...)`. The host sees that as an
35
+ * early process death and reports it as a stdin failure, so a name that is not
36
+ * installable turns into a misleading error far from the cause.
37
+ *
38
+ * It used to be `deepseek-proxy`, an agent that exists only in the upstream
39
+ * author's own environment; every fresh install therefore failed out of the box.
40
+ */
41
+ export const DEFAULT_AGENT = 'dsh-agy-mcp-executor';
42
+ const ModelConfig = z.object({
43
+ id: z.string().pattern(/^\S(?:.*\S)?$/).required(),
44
+ name: z.string().pattern(/^\S(?:.*\S)?$/),
45
+ // Kept for YAML/API compatibility; the selector intentionally does not render it.
46
+ description: z.string().hidden(),
47
+ contextWindow: z.natural().min(1).max(10_000_000),
48
+ });
49
+ const RetryPolicyConfig = z.object({
50
+ maxRetries: z.natural().max(5).default(5),
51
+ // Deliberately open-ended: the allowlist must be able to grow (AGY_INPUT_FAILED
52
+ // and AGY_SPAWN_FAILED were added on 2026-10-13) without rejecting every profile
53
+ // that was written against the previous list. Anything not in AGY_RETRYABLE_CODES
54
+ // is dropped by resolveAgyRetryPolicy with a process warning.
55
+ retryableCodes: z.array(z.string().pattern(/^[A-Z][A-Z0-9_]*$/)).min(1).default([...AGY_RETRYABLE_CODES]),
56
+ });
57
+ const PurposeRoute = z.object({
58
+ model: z.string().pattern(/^\S(?:.*\S)?$/),
59
+ agent: z.string().pattern(/^\S(?:.*\S)?$/),
60
+ reasoningEffort: z.union(['low', 'medium', 'high']),
61
+ });
62
+ const PurposeRoutes = z.object({
63
+ compaction: PurposeRoute,
64
+ sessionTitle: PurposeRoute,
65
+ });
66
+ export function createConfigSchema(defaults = {}) {
67
+ const defaultEnabled = defaults.enabled ?? false;
68
+ const defaultToolPolicy = defaults.toolPolicy ?? 'reject';
69
+ const schemaBase = z.object({
70
+ enabled: z.boolean().default(defaultEnabled).description('Enable AGY provider').volatile(),
71
+ // The route is fixed by this plugin and is not a user-facing setting.
72
+ provider: z.string().default('agy').description('Provider route id').hidden(),
73
+ model: z.string().default(DEFAULT_MODEL).description('Default model id (base, without -high/-medium/-low suffix)'),
74
+ // Explicit catalogs are an advanced YAML escape hatch; the normal UI uses discovery.
75
+ models: z.array(ModelConfig).default([]).description('Explicit model catalog; entries are base ids').hidden(),
76
+ visibleModels: z.array(z.string().pattern(/^\S(?:.*\S)?$/)).default([]).description('Visible models filter; empty shows all discovered models, non-empty only shows checked base ids'),
77
+ modelDiscovery: z.union(['auto', 'off']).default('auto').description('Discover models via agy models'),
78
+ modelDiscoveryTtlMs: z.number().min(1_000).max(3_600_000).default(300_000).description('Discovery cache TTL ms').hidden(),
79
+ modelDiscoveryTimeoutMs: z.number().min(100).max(30_000).default(10_000).description('Discovery timeout ms').hidden(),
80
+ toolPolicy: z.union(['reject', 'agy-owned', 'dsh-owned']).default(defaultToolPolicy).description('Tool ownership policy'),
81
+ mcpBridge: z.boolean().default(true).description('Expose DSH tools to AGY over MCP instead of embedding their schemas in the prompt'),
82
+ mcpToolAllowlist: z.array(z.string().pattern(/^\S(?:.*\S)?$/)).default([]).description('MCP tool projection allowlist; empty exposes every DSH tool'),
83
+ agent: z.string().default(DEFAULT_AGENT).description('AGY agent profile'),
84
+ agentPreset: z.union(AGENT_PRESET_IDS).description('Optional agent preset'),
85
+ workspaceRoot: z.string().pattern(/^\S(?:.*\S)?$/).description('Deprecated: use DSH session workspace').deprecated().hidden(),
86
+ agyPath: z.string().default('').description('AGY executable path').hidden(),
87
+ timeoutMs: z.number().min(1).max(3_600_000).default(900_000).description('Backstop wall clock per request ms; only an endless-output run can reach it').hidden(),
88
+ idleTimeoutMs: z.number().min(1).max(3_600_000).default(300_000).description('Inactivity budget per request ms; re-armed on every output line. Must stay below timeoutMs').hidden(),
89
+ stdinMode: z.union(['hold', 'close']).default('hold').description('Keep the request pipe open until AGY closes the turn (hold) or end it as soon as the frame is written (close)').hidden(),
90
+ sessionMode: z.union(['resume', 'full']).default('full').description('Session mode'),
91
+ sessionStorePath: z.string().default('').description('Durable sessionId to conversationId map path; empty uses DSH_HOME/agy-cli/sessions.json'),
92
+ minimumAgyVersion: z.string().pattern(/^\d+\.\d+\.\d+$/).default('1.1.15').description('Minimum AGY version').hidden(),
93
+ maxConcurrent: z.natural().min(1).max(64).default(4).description('Max concurrent AGY processes').hidden(),
94
+ maxQueue: z.natural().max(256).default(32).description('Max queue length').hidden(),
95
+ queueTimeoutMs: z.natural().max(3_600_000).default(30_000).description('Queue timeout ms').hidden(),
96
+ transport: z.union(['one-shot', 'persistent']).default('one-shot').description('Transport mode').hidden(),
97
+ persistentIdleTtlMs: z.number().min(0).max(3_600_000).default(30_000).description('Persistent idle TTL ms').hidden(),
98
+ persistentReadyTimeoutMs: z.number().min(1).max(60_000).default(10_000).description('Persistent ready timeout ms').hidden(),
99
+ persistentFallback: z.union(['never', 'before-accept']).default('before-accept').description('Persistent fallback policy').hidden(),
100
+ maxOutputBytes: z.natural().min(1_024).max(64 * 1024 * 1024).default(8 * 1024 * 1024).description('Max output bytes').hidden(),
101
+ maxEventLineLength: z.natural().min(1_024).max(8 * 1024 * 1024).default(1_048_576).description('Max event line length').hidden(),
102
+ inputFrameLimitBytes: z.natural().min(128).max(16 * 1024 * 1024).default(DEFAULT_INPUT_FRAME_LIMIT_BYTES).description('AGY input frame limit bytes').hidden(),
103
+ maxSingleToolResultBytes: z.natural().min(1_024).max(512 * 1024).default(DEFAULT_MAX_SINGLE_TOOL_RESULT_BYTES).description('Maximum serialized tool result bytes').hidden(),
104
+ maxHistoricalToolResultBytes: z.natural().min(1_024).max(2 * 1024 * 1024).default(DEFAULT_MAX_HISTORICAL_TOOL_RESULT_BYTES).description('Maximum historical tool result bytes').hidden(),
105
+ toolProtocolRepairRetries: z.natural().max(1).default(1).description('Structured tool protocol repair retries').hidden(),
106
+ toolProtocolPlainTextFallback: z.union(['off', 'final-message']).default('final-message').description('Plain text fallback after structured protocol repair').hidden(),
107
+ retryPolicy: RetryPolicyConfig.default({
108
+ maxRetries: 5,
109
+ retryableCodes: [...AGY_RETRYABLE_CODES],
110
+ }).hidden(),
111
+ purposeRoutes: PurposeRoutes.description('Purpose-specific overrides').hidden(),
112
+ // Default lead equals the default interval on purpose: agy only rotates a
113
+ // token it already considers expired, so there is no benefit to a wide
114
+ // window — it would just restart agy.exe on every tick without effect.
115
+ tokenKeepaliveMs: z.number().min(0).max(3_600_000).default(60_000).description('Keyring token keep-alive check interval ms; 0 disables it').hidden(),
116
+ tokenKeepaliveLeadMs: z.number().min(0).max(3_600_000).default(60_000).description('Renew the keyring token once it has less life than this ms').hidden(),
117
+ tokenKeepaliveCwd: z.string().description('Working directory for the renewal run; defaults to the user profile directory').hidden(),
118
+ imageInput: z.union(['off', 'experimental']).description('Image input mode'),
119
+ response: z.string().default('AGY mock provider is ready.').description('Mock response').hidden(),
120
+ delayMs: z.number().min(0).max(60_000).default(0).description('Mock delay ms').hidden(),
121
+ });
122
+ // Field-level `.volatile()` (used on `enabled` so the host Models settings
123
+ // page can project this Config into a namespace) is rejected by schemastery
124
+ // when the schema is wrapped in z.transform — the wrapper puts the object at
125
+ // a wildcard path (`$.*.enabled`) which the volatile placement rules treat as
126
+ // non-fixed. The suffix normalization that used to live here moved to the
127
+ // consumers: agy.ts:1164-1167 already normalizes model/models/visibleModels
128
+ // via normalizeModelId(), which covers every value this transform touched.
129
+ const schema = schemaBase;
130
+ const localized = schema.i18n({
131
+ 'zh-CN': {
132
+ enabled: { $description: '是否启用 AGY 提供方' },
133
+ provider: { $description: '提供方路由 ID(固定为 agy)' },
134
+ model: { $description: '默认模型 ID(基础名称,不含 -high/-medium/-low 后缀,推理强度另选)' },
135
+ models: { $description: '显式模型目录;条目为基础 ID,可覆盖名称与上下文窗口' },
136
+ visibleModels: { $description: '可见模型过滤;为空时显示全部发现模型,非空时仅显示勾选的基础 ID' },
137
+ modelDiscovery: { $description: '是否通过 agy models 自动发现模型' },
138
+ modelDiscoveryTtlMs: { $description: '模型发现缓存时间(毫秒)' },
139
+ modelDiscoveryTimeoutMs: { $description: '模型发现超时(毫秒)' },
140
+ toolPolicy: { $description: '工具所有权:reject=拒绝 DSH 工具, agy-owned=旧版 AGY 执行, dsh-owned=推荐 DSH 执行' },
141
+ mcpBridge: { $description: '通过 MCP 把 DSH 工具交给 AGY(推荐);关闭则退回把工具 schema 写进提示词的旧方式' },
142
+ mcpToolAllowlist: { $description: 'MCP 工具白名单;为空时暴露全部 DSH 工具' },
143
+ agent: { $description: 'AGY 代理名称,须为已安装的模板(如 dsh-agy-mcp-executor)' },
144
+ agentPreset: { $description: '代理能力预设' },
145
+ workspaceRoot: { $description: '已废弃:请使用 DSH 会话的项目目录,无需手动配置' },
146
+ agyPath: { $description: 'AGY 可执行文件路径,空则自动发现' },
147
+ timeoutMs: { $description: '单次请求的墙上时钟上限(毫秒)' },
148
+ idleTimeoutMs: { $description: '单次请求的无输出静默预算(毫秒);每有一行输出即重新计时' },
149
+ stdinMode: { $description: '请求管道收尾方式:hold=等 AGY 自己结束本轮再关(默认,避免中途无输出被判死), close=写完即关' },
150
+ sessionMode: { $description: '会话模式:full=每轮完整历史, resume=复用 AGY 会话' },
151
+ sessionStorePath: { $description: '会话映射(DSH 会话→AGY 对话)的落盘路径;留空用 DSH_HOME/agy-cli/sessions.json,让 resume 模式在宿主重启后仍能续话' },
152
+ minimumAgyVersion: { $description: '最低允许的 AGY 版本' },
153
+ maxConcurrent: { $description: '最大并发 AGY 进程数' },
154
+ maxQueue: { $description: '最大排队长度' },
155
+ queueTimeoutMs: { $description: '排队超时(毫秒)' },
156
+ transport: { $description: '传输模式:one-shot=每请求新进程, persistent=同会话复用 worker' },
157
+ persistentIdleTtlMs: { $description: '持久 worker 空闲回收时间(毫秒)' },
158
+ persistentReadyTimeoutMs: { $description: '持久 worker 就绪超时(毫秒)' },
159
+ persistentFallback: { $description: '持久失败回退策略' },
160
+ maxOutputBytes: { $description: '单次 AGY 输出最大字节' },
161
+ maxEventLineLength: { $description: '单行事件最大长度' },
162
+ inputFrameLimitBytes: { $description: 'AGY 单次输入帧上限(字节);超长工具结果会先裁剪' },
163
+ maxSingleToolResultBytes: { $description: '单个历史工具结果保留上限(字节)' },
164
+ maxHistoricalToolResultBytes: { $description: '所有历史工具结果合计保留上限(字节)' },
165
+ toolProtocolRepairRetries: { $description: 'DSH 工具协议返回非 JSON 时的修复重试次数' },
166
+ toolProtocolPlainTextFallback: { $description: '修复仍失败时是否将普通文本安全降级为最终消息' },
167
+ purposeRoutes: { $description: '按用途(压缩/标题)的模型覆盖' },
168
+ tokenKeepaliveMs: { $description: '凭据保活检查间隔(毫秒,默认 60 秒);0 表示关闭。到期前一个周期内才真正启动 agy 续期' },
169
+ tokenKeepaliveLeadMs: { $description: '凭据剩余有效期低于该毫秒数时自动续期(默认 60 秒)' },
170
+ imageInput: { $description: '图片输入:off=关闭, experimental=通过最小 view_file Agent 处理附件' },
171
+ },
172
+ en: {
173
+ enabled: { $description: 'Enable AGY provider' },
174
+ provider: { $description: 'Provider route id (always agy)' },
175
+ model: { $description: 'Default base model id (without -high/-medium/-low suffix; effort selected separately)' },
176
+ models: { $description: 'Explicit model catalog; entries are base ids' },
177
+ visibleModels: { $description: 'Visible models filter; empty shows all discovered base models, non-empty only shows checked ids' },
178
+ modelDiscovery: { $description: 'Auto-discover models via agy models' },
179
+ modelDiscoveryTtlMs: { $description: 'Discovery cache TTL (ms)' },
180
+ modelDiscoveryTimeoutMs: { $description: 'Discovery timeout (ms)' },
181
+ toolPolicy: { $description: 'Tool ownership: reject, agy-owned (legacy), dsh-owned (recommended)' },
182
+ agent: { $description: 'AGY agent profile; must be an installed template (e.g. dsh-agy-mcp-executor)' },
183
+ agentPreset: { $description: 'Agent capability preset' },
184
+ workspaceRoot: { $description: 'Deprecated: uses DSH session workspace, no manual path needed' },
185
+ agyPath: { $description: 'AGY executable path, empty auto-discovers' },
186
+ timeoutMs: { $description: 'Per-request wall-clock ceiling (ms)' },
187
+ idleTimeoutMs: { $description: 'Per-request inactivity budget (ms); re-armed on every output line' },
188
+ stdinMode: { $description: 'How the request pipe is retired: hold=wait for AGY to finish the turn (default), close=end right after the frame is written' },
189
+ sessionMode: { $description: 'Session mode: full or resume' },
190
+ sessionStorePath: { $description: 'Path of the durable DSH session to AGY conversation map; empty uses DSH_HOME/agy-cli/sessions.json so resume keeps working after a host restart' },
191
+ minimumAgyVersion: { $description: 'Minimum AGY version' },
192
+ maxConcurrent: { $description: 'Max concurrent AGY processes' },
193
+ maxQueue: { $description: 'Max queue length' },
194
+ queueTimeoutMs: { $description: 'Queue timeout (ms)' },
195
+ transport: { $description: 'Transport: one-shot or persistent' },
196
+ persistentIdleTtlMs: { $description: 'Persistent idle TTL (ms)' },
197
+ persistentReadyTimeoutMs: { $description: 'Persistent ready timeout (ms)' },
198
+ persistentFallback: { $description: 'Persistent fallback policy' },
199
+ maxOutputBytes: { $description: 'Max output bytes per AGY process' },
200
+ maxEventLineLength: { $description: 'Max event line length' },
201
+ inputFrameLimitBytes: { $description: 'AGY input frame limit in bytes; oversized tool results are compacted first' },
202
+ maxSingleToolResultBytes: { $description: 'Maximum retained bytes for one historical tool result' },
203
+ maxHistoricalToolResultBytes: { $description: 'Maximum combined retained bytes for historical tool results' },
204
+ toolProtocolRepairRetries: { $description: 'Repair retries when a DSH tool response is not JSON' },
205
+ toolProtocolPlainTextFallback: { $description: 'Safely treat plain text as a final message after repair' },
206
+ purposeRoutes: { $description: 'Purpose-specific model overrides' },
207
+ tokenKeepaliveMs: { $description: 'Keyring token keep-alive check interval (ms, default 60 s); 0 disables it. agy is only started on the tick inside the lead' },
208
+ tokenKeepaliveLeadMs: { $description: 'Renew the keyring token once it has less than this many ms of life left (default 60 s)' },
209
+ imageInput: { $description: 'Image input: off, or experimental through the minimal view_file Agent' },
210
+ },
211
+ });
212
+ return localized
213
+ .comment('其余字段在 cordis.patch.yml 中,请直接编辑对应段。 (dsh-agy-cli)');
214
+ }
215
+ /** Programmatic library default: enabled=false, toolPolicy=reject */
216
+ export const Config = createConfigSchema({ enabled: false, toolPolicy: 'reject' });
217
+ /** Bundle default for DSH profile plugin add: enabled=true, DSH owns tools. */
218
+ export const BundleConfig = createConfigSchema({ enabled: true, toolPolicy: 'dsh-owned' });
219
+ /**
220
+ * Resolve the effective catalog while keeping the 0.1.0 `model` setting
221
+ * compatible. Catalog membership is advisory; unknown exact model ids remain
222
+ * valid request targets and are handled by each adapter's resolveModel().
223
+ */
224
+ export function configuredModels(config = {}) {
225
+ const fallbackId = config.model?.trim() || DEFAULT_MODEL;
226
+ const entries = config.models !== undefined && config.models.length > 0
227
+ ? config.models
228
+ : [{ id: fallbackId }];
229
+ const catalog = [];
230
+ const seen = new Set();
231
+ for (const entry of entries) {
232
+ const id = entry.id.trim();
233
+ if (id.length === 0 || seen.has(id))
234
+ continue;
235
+ seen.add(id);
236
+ catalog.push({ ...entry, id });
237
+ }
238
+ if (!seen.has(fallbackId))
239
+ catalog.push({ id: fallbackId });
240
+ return catalog;
241
+ }
242
+ /**
243
+ * Read a boolean config field that may have been projected as a volatile live
244
+ * reference.
245
+ *
246
+ * `enabled` carries `.volatile()` so the host's SettingsForms can project this
247
+ * Config into the `dsh-agy-cli` settings namespace — without at least one
248
+ * volatile field the Models page does not render our row at all. The cost is
249
+ * that the host hands the plugin a *reference* object (`{ get() }`, written
250
+ * through a symbol key) instead of the plain boolean the profile declares, so
251
+ * `config.enabled === true` is false no matter what the user configured.
252
+ *
253
+ * That comparison used to gate `apply()`: the directory and the HTTP routes
254
+ * were registered (they run before the gate) while the provider adapter never
255
+ * was, i.e. the plugin was half-mounted and `/plugins/agy-cli/status` reported
256
+ * `enabled: {}`. Read the flag through here instead of comparing directly.
257
+ */
258
+ export function readConfigFlag(value) {
259
+ if (value === true)
260
+ return true;
261
+ if (value === false || value === undefined || value === null)
262
+ return false;
263
+ if (typeof value === 'object') {
264
+ const get = value.get;
265
+ if (typeof get === 'function') {
266
+ try {
267
+ return get.call(value) === true;
268
+ }
269
+ catch {
270
+ return false;
271
+ }
272
+ }
273
+ }
274
+ return false;
275
+ }
276
+ /** Normalize a possibly suffixed model id to its base (strip -low/-medium/-high). */
277
+ export function normalizeModelId(id) {
278
+ return id.replace(/-(?:low|medium|high)$/i, '');
279
+ }
280
+ /** Extract effort suffix from a model id, if present. */
281
+ export function extractModelEffort(id) {
282
+ const m = /-(low|medium|high)$/i.exec(id);
283
+ if (!m || !m[1])
284
+ return undefined;
285
+ return m[1].toLowerCase();
286
+ }
287
+ /** Filter catalog by visibleModels (empty = all). */
288
+ export function filterVisibleModels(models, visibleModels) {
289
+ if (visibleModels === undefined || visibleModels.length === 0)
290
+ return models;
291
+ const allow = new Set(visibleModels.map(normalizeModelId));
292
+ return models.filter(m => allow.has(normalizeModelId(m.id)));
293
+ }
294
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1,22 @@
1
+ /** Stable codes used at the Provider boundary and in machine diagnostics. */
2
+ export declare const MODEL_DISCOVERY_FAILED_CODE: "MODEL_DISCOVERY_FAILED";
3
+ export declare const MODEL_DISCOVERY_EMPTY_CODE: "MODEL_DISCOVERY_EMPTY";
4
+ export declare const MODEL_DISCOVERY_TIMEOUT_CODE: "MODEL_DISCOVERY_TIMEOUT";
5
+ export declare const MODEL_DISCOVERY_OUTPUT_LIMIT_CODE: "MODEL_DISCOVERY_OUTPUT_LIMIT";
6
+ export declare const UNSUPPORTED_REASONING_EFFORT_CODE: "UNSUPPORTED_REASONING_EFFORT";
7
+ export declare const UNSUPPORTED_TOOLS_CODE: "UNSUPPORTED_TOOLS";
8
+ export declare const AGY_INTERNAL_TOOL_EVENT_CODE: "AGY_INTERNAL_TOOL_EVENT";
9
+ export declare const PERMISSION_REQUIRED_CODE: "PERMISSION_REQUIRED";
10
+ export declare const DSH_CONTEXT_UNAVAILABLE_CODE: "DSH_CONTEXT_UNAVAILABLE";
11
+ export declare const DSH_SESSION_REQUIRED_CODE: "DSH_SESSION_REQUIRED";
12
+ export declare const DSH_SESSION_UNAVAILABLE_CODE: "DSH_SESSION_UNAVAILABLE";
13
+ export declare const DSH_SESSION_UNKNOWN_CODE: "DSH_SESSION_UNKNOWN";
14
+ export declare const DSH_SESSION_INVALID_CODE: "DSH_SESSION_INVALID";
15
+ export declare const DSH_WORKSPACE_UNAVAILABLE_CODE: "DSH_WORKSPACE_UNAVAILABLE";
16
+ export declare const DSH_WORKSPACE_MISMATCH_CODE: "DSH_WORKSPACE_MISMATCH";
17
+ export declare const DSH_SANDBOX_UNAVAILABLE_CODE: "DSH_SANDBOX_UNAVAILABLE";
18
+ export declare const DSH_PERMISSION_UNAVAILABLE_CODE: "DSH_PERMISSION_UNAVAILABLE";
19
+ export declare const DSH_APPROVAL_UNAVAILABLE_CODE: "DSH_APPROVAL_UNAVAILABLE";
20
+ export type ModelDiscoveryErrorCode = typeof MODEL_DISCOVERY_FAILED_CODE | typeof MODEL_DISCOVERY_EMPTY_CODE | typeof MODEL_DISCOVERY_TIMEOUT_CODE | typeof MODEL_DISCOVERY_OUTPUT_LIMIT_CODE;
21
+ export declare function isModelDiscoveryErrorCode(value: unknown): value is ModelDiscoveryErrorCode;
22
+ //# sourceMappingURL=error-codes.d.ts.map
@@ -0,0 +1,29 @@
1
+ /** Stable codes used at the Provider boundary and in machine diagnostics. */
2
+ export const MODEL_DISCOVERY_FAILED_CODE = 'MODEL_DISCOVERY_FAILED';
3
+ export const MODEL_DISCOVERY_EMPTY_CODE = 'MODEL_DISCOVERY_EMPTY';
4
+ export const MODEL_DISCOVERY_TIMEOUT_CODE = 'MODEL_DISCOVERY_TIMEOUT';
5
+ export const MODEL_DISCOVERY_OUTPUT_LIMIT_CODE = 'MODEL_DISCOVERY_OUTPUT_LIMIT';
6
+ export const UNSUPPORTED_REASONING_EFFORT_CODE = 'UNSUPPORTED_REASONING_EFFORT';
7
+ export const UNSUPPORTED_TOOLS_CODE = 'UNSUPPORTED_TOOLS';
8
+ export const AGY_INTERNAL_TOOL_EVENT_CODE = 'AGY_INTERNAL_TOOL_EVENT';
9
+ export const PERMISSION_REQUIRED_CODE = 'PERMISSION_REQUIRED';
10
+ export const DSH_CONTEXT_UNAVAILABLE_CODE = 'DSH_CONTEXT_UNAVAILABLE';
11
+ export const DSH_SESSION_REQUIRED_CODE = 'DSH_SESSION_REQUIRED';
12
+ export const DSH_SESSION_UNAVAILABLE_CODE = 'DSH_SESSION_UNAVAILABLE';
13
+ export const DSH_SESSION_UNKNOWN_CODE = 'DSH_SESSION_UNKNOWN';
14
+ export const DSH_SESSION_INVALID_CODE = 'DSH_SESSION_INVALID';
15
+ export const DSH_WORKSPACE_UNAVAILABLE_CODE = 'DSH_WORKSPACE_UNAVAILABLE';
16
+ export const DSH_WORKSPACE_MISMATCH_CODE = 'DSH_WORKSPACE_MISMATCH';
17
+ export const DSH_SANDBOX_UNAVAILABLE_CODE = 'DSH_SANDBOX_UNAVAILABLE';
18
+ export const DSH_PERMISSION_UNAVAILABLE_CODE = 'DSH_PERMISSION_UNAVAILABLE';
19
+ export const DSH_APPROVAL_UNAVAILABLE_CODE = 'DSH_APPROVAL_UNAVAILABLE';
20
+ const MODEL_DISCOVERY_ERROR_CODES = [
21
+ MODEL_DISCOVERY_FAILED_CODE,
22
+ MODEL_DISCOVERY_EMPTY_CODE,
23
+ MODEL_DISCOVERY_TIMEOUT_CODE,
24
+ MODEL_DISCOVERY_OUTPUT_LIMIT_CODE,
25
+ ];
26
+ export function isModelDiscoveryErrorCode(value) {
27
+ return typeof value === 'string' && MODEL_DISCOVERY_ERROR_CODES.includes(value);
28
+ }
29
+ //# sourceMappingURL=error-codes.js.map
@@ -0,0 +1,60 @@
1
+ import type { AttachmentStore } from '@deepseek-ai/dsh-attachment';
2
+ import type { GenerateOptions } from '@deepseek-ai/dsh-llm';
3
+ export declare const IMAGE_MEDIA_TYPES: readonly ["image/png", "image/jpeg", "image/webp", "image/gif"];
4
+ /** Placeholder media type for a history image of an unsupported kind. */
5
+ export declare const FALLBACK_IMAGE_MEDIA_TYPE: AgyImageMediaType;
6
+ export declare const DEFAULT_IMAGE_MAX_BYTES: number;
7
+ export declare const DEFAULT_IMAGE_MAX_COUNT = 4;
8
+ export type AgyImageMediaType = typeof IMAGE_MEDIA_TYPES[number];
9
+ /**
10
+ * Images carried by the turn being answered are staged into a per-request temp
11
+ * directory and counted against `DEFAULT_IMAGE_MAX_COUNT`. Images from earlier
12
+ * turns are not: the request only accepts a handful of new ones, and rewriting
13
+ * every historical attachment on every turn is pure cost. They are materialized
14
+ * once into this stable cache instead, so their placeholder can still be opened
15
+ * on demand by the image-view Agent (or by the user in Explorer) long after the
16
+ * turn that uploaded them is over.
17
+ */
18
+ export declare const IMAGE_HISTORY_CACHE_DIR: string;
19
+ export type AgyImageBridgeErrorCode = 'IMAGE_ATTACHMENT_UNAVAILABLE' | 'IMAGE_AGENT_UNSUPPORTED' | 'IMAGE_READ_FAILED' | 'IMAGE_UNSUPPORTED_MEDIA_TYPE' | 'IMAGE_SIZE_LIMIT' | 'IMAGE_STAGING_FAILED';
20
+ export declare class AgyImageBridgeError extends Error {
21
+ readonly code: AgyImageBridgeErrorCode;
22
+ constructor(message: string, code: AgyImageBridgeErrorCode, options?: ErrorOptions);
23
+ }
24
+ export type AgyImageAttachmentStore = Pick<AttachmentStore, 'readImage'>;
25
+ export interface PreparedAgyPrompts {
26
+ fullPrompt: string;
27
+ /** Precomputed only when image placeholders are present; text-only keeps the old lazy path. */
28
+ turnPrompt: string | undefined;
29
+ /** Temp directory holding this turn's images; removed as soon as the turn ends. */
30
+ imageDirectory: string | undefined;
31
+ /** Stable cache holding earlier turns' images; never removed by a turn. */
32
+ imageCacheDirectory: string | undefined;
33
+ /** Exact staged files used to validate the dedicated image Agent's internal view_file events. */
34
+ imagePaths: readonly string[];
35
+ /** True when this request replaced at least one image block with a placeholder. */
36
+ bridgeActive: boolean;
37
+ cleanup: () => Promise<void>;
38
+ }
39
+ export interface ImageBridgeOptions {
40
+ enabled: boolean;
41
+ /** Only a bundled preset with a verified view_file whitelist may read staged images. */
42
+ agentCanViewFile: boolean;
43
+ attachmentStore: AgyImageAttachmentStore | undefined;
44
+ signal?: AbortSignal;
45
+ maxBytes?: number;
46
+ maxCount?: number;
47
+ }
48
+ /**
49
+ * Prepare text prompts for the experimental file bridge.
50
+ *
51
+ * Only the turn being answered is staged: the place budget belongs to one
52
+ * message, and a conversation accumulates images forever, so counting the whole
53
+ * replayed history used to kill every later turn once a fifth image existed.
54
+ * Earlier turns keep a placeholder that still points at a real file under
55
+ * `IMAGE_HISTORY_CACHE_DIR`, so nothing is thrown away — the image-view Agent
56
+ * can open it the moment the model actually needs it, one turn or fifty turns
57
+ * later, and the user can open the same path in Explorer.
58
+ */
59
+ export declare function prepareAgyPrompts(options: Pick<GenerateOptions, 'messages' | 'system'>, bridgeOptions: ImageBridgeOptions): Promise<PreparedAgyPrompts>;
60
+ //# sourceMappingURL=image-bridge.d.ts.map