qlogicagent 2.1.0 → 2.3.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.
Files changed (59) hide show
  1. package/dist/agent.js +10 -9
  2. package/dist/cli.js +227 -209
  3. package/dist/contracts.js +1 -1
  4. package/dist/index.js +226 -208
  5. package/dist/orchestration.js +13 -12
  6. package/dist/types/agent/constants.d.ts +4 -53
  7. package/dist/types/agent/tunable-defaults.d.ts +221 -0
  8. package/dist/types/agent/types.d.ts +3 -1
  9. package/dist/types/cli/stdio-server.d.ts +52 -1
  10. package/dist/types/cli/tool-bootstrap.d.ts +8 -0
  11. package/dist/types/contracts/index.d.ts +0 -1
  12. package/dist/types/contracts/todo.d.ts +8 -21
  13. package/dist/types/llm/adapters/aliyun-oss-file-upload-adapter.d.ts +44 -0
  14. package/dist/types/llm/adapters/gemini-file-upload-adapter.d.ts +26 -0
  15. package/dist/types/llm/adapters/hub-oss-file-upload-adapter.d.ts +29 -0
  16. package/dist/types/llm/adapters/index.d.ts +10 -0
  17. package/dist/types/llm/adapters/openai-file-upload-adapter.d.ts +38 -0
  18. package/dist/types/llm/adapters/volcengine-file-upload-adapter.d.ts +24 -0
  19. package/dist/types/llm/file-upload-service.d.ts +68 -0
  20. package/dist/types/llm/transports/anthropic-messages.d.ts +4 -0
  21. package/dist/types/llm/transports/gemini-generatecontent.d.ts +4 -0
  22. package/dist/types/llm/transports/media-resolve.d.ts +37 -12
  23. package/dist/types/llm/transports/openai-chat.d.ts +4 -0
  24. package/dist/types/llm/transports/openai-responses.d.ts +3 -0
  25. package/dist/types/llm/transports/volcengine-responses.d.ts +4 -0
  26. package/dist/types/orchestration/skill-improvement.d.ts +39 -8
  27. package/dist/types/orchestration/subagent/fork-subagent.d.ts +2 -2
  28. package/dist/types/orchestration/tool-loop/tool-schema.d.ts +1 -0
  29. package/dist/types/protocol/methods.d.ts +70 -0
  30. package/dist/types/protocol/notifications.d.ts +61 -0
  31. package/dist/types/runtime/execution/dream-category-context.d.ts +1 -1
  32. package/dist/types/runtime/hooks/memory-hooks.d.ts +0 -3
  33. package/dist/types/runtime/hooks/skill-recall-hooks.d.ts +2 -4
  34. package/dist/types/runtime/infra/agent-paths.d.ts +6 -0
  35. package/dist/types/runtime/infra/index.d.ts +3 -1
  36. package/dist/types/runtime/infra/media-persistence.d.ts +71 -0
  37. package/dist/types/runtime/infra/project-instructions-store.d.ts +30 -0
  38. package/dist/types/runtime/infra/project-plan-store.d.ts +27 -0
  39. package/dist/types/runtime/infra/project-store.d.ts +36 -0
  40. package/dist/types/runtime/infra/skill-injector.d.ts +9 -2
  41. package/dist/types/skills/index.d.ts +2 -4
  42. package/dist/types/skills/memory/categories.d.ts +5 -0
  43. package/dist/types/skills/memory/memdir.d.ts +6 -1
  44. package/dist/types/skills/memory/recall-category-filter.d.ts +1 -1
  45. package/dist/types/skills/permissions/group-security-policy.d.ts +15 -0
  46. package/dist/types/skills/permissions/index.d.ts +1 -0
  47. package/dist/types/skills/plugins/plugin-loader.d.ts +5 -0
  48. package/dist/types/skills/portable-tool.d.ts +13 -2
  49. package/dist/types/skills/skill-system/skill-source.d.ts +65 -0
  50. package/dist/types/skills/tools/plan-mode-tool.d.ts +1 -1
  51. package/dist/types/skills/tools/read-tool.d.ts +2 -2
  52. package/dist/types/skills/tools/task-tool.d.ts +64 -75
  53. package/dist/types/transport/acp-server.d.ts +2 -0
  54. package/package.json +1 -1
  55. package/dist/types/contracts/planner.d.ts +0 -35
  56. package/dist/types/orchestration/error-handling/failover-error.d.ts +0 -33
  57. package/dist/types/skills/memory/memory-write-gate.d.ts +0 -46
  58. package/dist/types/skills/memory/memory-write-hook.d.ts +0 -44
  59. package/dist/types/skills/todo-tool.d.ts +0 -72
@@ -41,6 +41,8 @@ export declare class StdioServer {
41
41
  private sessionState;
42
42
  private currentMediaApiKeys;
43
43
  private taskStore;
44
+ /** Media auto-download service — persists generated media files locally. */
45
+ private mediaPersistence;
44
46
  /** Session-scoped memory prefetch state (LRU dedup + byte limit). */
45
47
  private memoryPrefetchState;
46
48
  /** QMemory adapter (when QMEMORY_BASE_URL env is set). Used by Dream hippocampus bridge. */
@@ -49,7 +51,6 @@ export declare class StdioServer {
49
51
  /** MEMDIR file-based memory (CC memdir parity). */
50
52
  private memdir;
51
53
  /** Memory write gate state (P2+P3: category gate + supersedes). */
52
- private memoryWriteState;
53
54
  private fileWatcher;
54
55
  /** Pending ask_user requests waiting for host response */
55
56
  private pendingAskUser;
@@ -91,6 +92,11 @@ export declare class StdioServer {
91
92
  * Always returns the InitializeResult shape.
92
93
  */
93
94
  private handleInitialize;
95
+ /**
96
+ * Ensure a default project exists on first start.
97
+ * Called from both legacy handleInitialize and ACP acpHandleInitialize.
98
+ */
99
+ private ensureDefaultProject;
94
100
  /**
95
101
  * `thread.create` — create a new thread (session container).
96
102
  * Maps threadId → sessionId for the underlying session system.
@@ -172,6 +178,16 @@ export declare class StdioServer {
172
178
  * `config.update` — Update agent runtime configuration (merges into settings.json).
173
179
  */
174
180
  private handleConfigUpdate;
181
+ /**
182
+ * `config.tunables` — Return all tunable default values with their current overrides.
183
+ */
184
+ private handleConfigTunables;
185
+ /**
186
+ * `config.updateTunable` — Write a single tunable override into settings.json.tunables.
187
+ * Params: { key: string, value: number | boolean | string }
188
+ * Only keys that exist in TunableDefaults are accepted (validation).
189
+ */
190
+ private handleConfigUpdateTunable;
175
191
  /**
176
192
  * `todos.list` — Query current todo items and summary.
177
193
  * Invokes the registered todo tool's list action.
@@ -299,4 +315,39 @@ export declare class StdioServer {
299
315
  private acpHandleProductResume;
300
316
  private acpHandleProductStatus;
301
317
  private acpHandleTeamDelegate;
318
+ private handleProjectCreate;
319
+ private handleProjectList;
320
+ private handleProjectDelete;
321
+ private handleProjectRename;
322
+ private handleProjectArchive;
323
+ private handleProjectUnarchive;
324
+ private handleProjectArchiveByGroup;
325
+ private handleSessionSwitchProject;
326
+ private handleSessionGetState;
327
+ private getProjectInstructionsStore;
328
+ private handleInstructionsList;
329
+ private handleInstructionsRead;
330
+ private handleInstructionsWrite;
331
+ private handleInstructionsDelete;
332
+ private handleSkillsList;
333
+ /** Extract version and description from a SKILL.md frontmatter. */
334
+ private extractSkillMeta;
335
+ private handleSkillsActivate;
336
+ private handleSkillsDeactivate;
337
+ /**
338
+ * `skills.delete` — Permanently remove a skill from project or global scope.
339
+ * Params: { name: string, scope?: "project" | "global" }
340
+ * Default scope: "project"
341
+ */
342
+ private handleSkillsDelete;
343
+ /**
344
+ * `skills.promote` — Copy a project-level skill to global (user-level).
345
+ * Params: { name: string, keepLocal?: boolean }
346
+ * By default removes the project-level copy after promoting.
347
+ */
348
+ private handleSkillsPromote;
349
+ private handleSkillsStats;
350
+ private getProjectPlanStore;
351
+ private handlePlansList;
352
+ private handlePlansGet;
302
353
  }
@@ -1,16 +1,24 @@
1
1
  import type { PortableTool } from "../skills/portable-tool.js";
2
+ import { type TaskToolHooks } from "../skills/tools/task-tool.js";
2
3
  import { type ExecProgress } from "../skills/tools/exec-tool.js";
3
4
  import type { AgentLogger } from "../agent/types.js";
4
5
  import { type AskUserQuestion } from "../skills/tools/ask-user-tool.js";
5
6
  import type { MediaClient } from "../llm/media-client.js";
6
7
  import type { MediaCapability } from "../llm/provider-def.js";
7
8
  import type { ProviderToolAPI } from "../llm/provider-tool-api.js";
9
+ /** Enable or disable group security mode (blocks sensitive file access). */
10
+ export declare function setGroupSecurityMode(enabled: boolean): void;
8
11
  /**
9
12
  * Set the provider's tool API for C-level cascade.
10
13
  * When set, web_search tool will try provider-native search first,
11
14
  * falling back to SearXNG. Called from stdio-server per session.
12
15
  */
13
16
  export declare function setProviderToolAPI(api: ProviderToolAPI | undefined): void;
17
+ /**
18
+ * Set task tool lifecycle hooks. Called from stdio-server when session starts.
19
+ * Connects planning-task events to the HookRegistry.
20
+ */
21
+ export declare function setTaskToolHooks(hooks: TaskToolHooks | undefined): void;
14
22
  /**
15
23
  * Set the ask_user callback. The host (Electron / test harness) provides
16
24
  * an implementation that presents questions to the user and returns answers.
@@ -4,6 +4,5 @@
4
4
  * These types are only consumed within qlogicagent itself (agent runtime + hub).
5
5
  * They were removed from the public npm package to slim the cross-repo API surface.
6
6
  */
7
- export * from "./planner.js";
8
7
  export * from "./todo.js";
9
8
  export * from "./hooks.js";
@@ -1,23 +1,10 @@
1
+ import type { TaskItem, TaskListSummary } from "../skills/tools/task-tool.js";
2
+ import { summarizeTaskList } from "../skills/tools/task-tool.js";
1
3
  export declare const TODO_ITEM_STATUS_VALUES: readonly ["not-started", "in-progress", "completed"];
2
4
  export type TodoItemStatus = (typeof TODO_ITEM_STATUS_VALUES)[number];
3
- export interface TodoItem {
4
- id: number;
5
- title: string;
6
- status: TodoItemStatus;
7
- /** Detailed task description (V2). */
8
- description?: string;
9
- /** Owner agent/subagent identifier for per-agent isolation (V2). */
10
- owner?: string;
11
- /** IDs of tasks that must complete before this one can start (V2). */
12
- blockedBy?: number[];
13
- /** IDs of tasks this one blocks from starting (V2). */
14
- blocks?: number[];
15
- }
16
- export interface TodoListSummary {
17
- total: number;
18
- completed: number;
19
- inProgress: number;
20
- notStarted: number;
21
- blocked: number;
22
- }
23
- export declare function summarizeTodoList(items: readonly TodoItem[]): TodoListSummary;
5
+ /** @deprecated Use TaskItem from task-tool.ts */
6
+ export type TodoItem = TaskItem;
7
+ /** @deprecated Use TaskListSummary from task-tool.ts */
8
+ export type TodoListSummary = TaskListSummary;
9
+ /** @deprecated Use summarizeTaskList from task-tool.ts */
10
+ export declare const summarizeTodoList: typeof summarizeTaskList;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Aliyun OSS File Upload Adapter — direct upload to Alibaba Cloud OSS.
3
+ *
4
+ * Uploads files directly to OSS bucket using V1 signature (HMAC-SHA1).
5
+ * No external dependencies — uses Node.js crypto + fetch.
6
+ *
7
+ * This is the **universal fallback adapter** for providers without a native
8
+ * File Upload API (e.g. Anthropic). Ensures ALL file handling goes through
9
+ * upload — never base64 inline.
10
+ *
11
+ * Environment variables:
12
+ * OSS_ACCESS_KEY_ID — Aliyun AccessKey ID
13
+ * OSS_ACCESS_KEY_SECRET — Aliyun AccessKey Secret
14
+ * OSS_BUCKET — Bucket name (default: "qlogicagent")
15
+ * OSS_REGION — Region (default: "cn-beijing")
16
+ * OSS_ENDPOINT — Custom endpoint (default: derived from region)
17
+ */
18
+ import type { FileUploadAdapter, FileUploadResult } from "../file-upload-service.js";
19
+ export interface AliyunOSSFileUploadConfig {
20
+ /** Aliyun AccessKey ID. Required. */
21
+ accessKeyId: string;
22
+ /** Aliyun AccessKey Secret. Required. */
23
+ accessKeySecret: string;
24
+ /** OSS Bucket name. Default: "qlogicagent". */
25
+ bucket?: string;
26
+ /** OSS Region. Default: "cn-beijing". */
27
+ region?: string;
28
+ /** Custom OSS endpoint. Default: "{bucket}.oss-{region}.aliyuncs.com". */
29
+ endpoint?: string;
30
+ /** Upload path prefix. Default: "media". */
31
+ pathPrefix?: string;
32
+ /** Timeout ms. Default: 120_000. */
33
+ timeoutMs?: number;
34
+ }
35
+ /**
36
+ * Create an AliyunOSSFileUploadAdapter from environment variables.
37
+ * Returns undefined if required env vars (OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET) are missing.
38
+ */
39
+ export declare function createAliyunOSSAdapterFromEnv(): AliyunOSSFileUploadAdapter | undefined;
40
+ export declare class AliyunOSSFileUploadAdapter implements FileUploadAdapter {
41
+ private readonly config;
42
+ constructor(config: AliyunOSSFileUploadConfig);
43
+ uploadFile(buffer: Buffer, filename: string, mimeType: string, _apiKey: string, signal?: AbortSignal): Promise<FileUploadResult>;
44
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Gemini File Upload Adapter.
3
+ *
4
+ * Implements the Google Gemini 2-step resumable upload protocol
5
+ * into the unified FileUploadAdapter interface.
6
+ *
7
+ * Protocol:
8
+ * 1. POST /upload/v1beta/files — initiate, get upload URL
9
+ * 2. PUT {uploadUrl} — send bytes, finalize
10
+ *
11
+ * Returns a file URI (e.g. "files/abc123") that can be used in
12
+ * generateContent requests as a file reference.
13
+ */
14
+ import type { FileUploadAdapter, FileUploadResult } from "../file-upload-service.js";
15
+ export interface GeminiFileUploadConfig {
16
+ /** Base URL (e.g. "https://generativelanguage.googleapis.com/v1beta") */
17
+ baseUrl: string;
18
+ /** Timeout ms. Default: 180_000. */
19
+ timeoutMs?: number;
20
+ }
21
+ export declare class GeminiFileUploadAdapter implements FileUploadAdapter {
22
+ private readonly config;
23
+ constructor(config: GeminiFileUploadConfig);
24
+ uploadFile(buffer: Buffer, filename: string, mimeType: string, apiKey: string, signal?: AbortSignal): Promise<FileUploadResult>;
25
+ private waitForProcessing;
26
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Hub OSS File Upload Adapter — for providers without native File API (e.g. Anthropic).
3
+ *
4
+ * Uploads local files to the Hub's OSS relay endpoint, which stores them in
5
+ * cloud object storage (Aliyun OSS / Tencent COS) and returns a public URL.
6
+ * The LLM provider can then access the file via this public URL.
7
+ *
8
+ * This enables Anthropic (which only supports base64 inline or public URL)
9
+ * to handle large files that exceed the base64 size limit (20MB).
10
+ *
11
+ * Endpoint: POST {hubBaseUrl}/api/v1/files/upload
12
+ * Returns: { url: "https://oss-bucket.oss-cn-xxx.aliyuncs.com/..." }
13
+ */
14
+ import type { FileUploadAdapter, FileUploadResult } from "../file-upload-service.js";
15
+ export interface HubOSSFileUploadConfig {
16
+ /** Hub API base URL (e.g. "https://hub.xiaozhiclaw.com" or from env). */
17
+ hubBaseUrl: string;
18
+ /** Hub API key for authentication. */
19
+ hubApiKey?: string;
20
+ /** Timeout ms. Default: 120_000. */
21
+ timeoutMs?: number;
22
+ /** Provider name for result metadata. Default: "hub-oss". */
23
+ provider?: string;
24
+ }
25
+ export declare class HubOSSFileUploadAdapter implements FileUploadAdapter {
26
+ private readonly config;
27
+ constructor(config: HubOSSFileUploadConfig);
28
+ uploadFile(buffer: Buffer, filename: string, mimeType: string, _apiKey: string, signal?: AbortSignal): Promise<FileUploadResult>;
29
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * File Upload Adapters — barrel export.
3
+ *
4
+ * Provider-specific implementations of the FileUploadAdapter interface.
5
+ */
6
+ export { OpenAIFileUploadAdapter, type OpenAIFileUploadConfig } from "./openai-file-upload-adapter.js";
7
+ export { VolcengineFileUploadAdapter, type VolcengineFileUploadConfig } from "./volcengine-file-upload-adapter.js";
8
+ export { GeminiFileUploadAdapter, type GeminiFileUploadConfig } from "./gemini-file-upload-adapter.js";
9
+ export { HubOSSFileUploadAdapter, type HubOSSFileUploadConfig } from "./hub-oss-file-upload-adapter.js";
10
+ export { AliyunOSSFileUploadAdapter, type AliyunOSSFileUploadConfig, createAliyunOSSAdapterFromEnv } from "./aliyun-oss-file-upload-adapter.js";
@@ -0,0 +1,38 @@
1
+ /**
2
+ * OpenAI-compatible File Upload Adapter.
3
+ *
4
+ * Implements FileUploadAdapter for providers using the standard
5
+ * POST /v1/files multipart upload endpoint:
6
+ * - OpenAI
7
+ * - Kimi (Moonshot)
8
+ * - Minimax
9
+ * - Qwen (via DashScope compatible endpoint)
10
+ * - GLM (Zhipu)
11
+ * - Any OpenAI-API-compatible provider
12
+ *
13
+ * The uploaded file gets a file_id which can be referenced in messages.
14
+ * Some providers also return a direct download URL.
15
+ */
16
+ import type { FileUploadAdapter, FileUploadResult } from "../file-upload-service.js";
17
+ export interface OpenAIFileUploadConfig {
18
+ /** Base URL (e.g. "https://api.openai.com/v1" or "https://api.moonshot.cn/v1") */
19
+ baseUrl: string;
20
+ /** Provider name for result metadata. */
21
+ provider: string;
22
+ /** Extra headers to include (e.g. for Minimax group_id). */
23
+ extraHeaders?: Record<string, string>;
24
+ /** Upload purpose (default: "file-extract" for document understanding). */
25
+ defaultPurpose?: string;
26
+ /**
27
+ * Whether the provider returns a download URL in the upload response.
28
+ * If false, constructs URL from file_id (provider-specific).
29
+ */
30
+ returnsUrl?: boolean;
31
+ /** Timeout for upload request (ms). Default: 120_000. */
32
+ timeoutMs?: number;
33
+ }
34
+ export declare class OpenAIFileUploadAdapter implements FileUploadAdapter {
35
+ private readonly config;
36
+ constructor(config: OpenAIFileUploadConfig);
37
+ uploadFile(buffer: Buffer, filename: string, mimeType: string, apiKey: string, signal?: AbortSignal): Promise<FileUploadResult>;
38
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Volcengine File Upload Adapter.
3
+ *
4
+ * Wraps the Volcengine /v3/files endpoint into the unified
5
+ * FileUploadAdapter interface.
6
+ *
7
+ * Volcengine returns a file_id that can be used in API messages
8
+ * as a file reference. Files uploaded this way can be referenced in
9
+ * multimodal inputs via the file_id field.
10
+ */
11
+ import type { FileUploadAdapter, FileUploadResult } from "../file-upload-service.js";
12
+ export interface VolcengineFileUploadConfig {
13
+ /** Base URL (e.g. "https://ark.cn-beijing.volces.com/api") */
14
+ baseUrl: string;
15
+ /** Upload purpose. Default: "user_data". */
16
+ defaultPurpose?: string;
17
+ /** Timeout ms. Default: 120_000. */
18
+ timeoutMs?: number;
19
+ }
20
+ export declare class VolcengineFileUploadAdapter implements FileUploadAdapter {
21
+ private readonly config;
22
+ constructor(config: VolcengineFileUploadConfig);
23
+ uploadFile(buffer: Buffer, filename: string, mimeType: string, apiKey: string, signal?: AbortSignal): Promise<FileUploadResult>;
24
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * FileUploadService — Unified file upload abstraction for all LLM providers.
3
+ *
4
+ * Replaces the base64 approach in media-resolve.ts. When a local URL is
5
+ * encountered, this service uploads the file to the current provider's
6
+ * File API and returns a public URL or file_id.
7
+ *
8
+ * Supported providers:
9
+ * - OpenAI-compatible (OpenAI, Kimi, Minimax, Qwen, GLM) — POST /v1/files
10
+ * - Volcengine — POST /v3/files
11
+ * - Google Gemini — Resumable upload protocol
12
+ *
13
+ * Architecture:
14
+ * Transport layer calls resolveLocalMedia() before sending messages.
15
+ * resolveLocalMedia() fetches local content and uploads to provider,
16
+ * returning a public URL the LLM can access.
17
+ */
18
+ export interface FileUploadResult {
19
+ /** Public URL accessible by the LLM provider. */
20
+ url: string;
21
+ /** Provider-specific file identifier (for reference/deletion). */
22
+ fileId: string;
23
+ /** Original filename. */
24
+ filename: string;
25
+ /** File size in bytes. */
26
+ bytes: number;
27
+ /** MIME type of the uploaded file. */
28
+ mimeType: string;
29
+ /** Provider that stored the file. */
30
+ provider: string;
31
+ }
32
+ /**
33
+ * Provider-specific upload adapter.
34
+ * Each transport implements this to upload files to its own File API.
35
+ */
36
+ export interface FileUploadAdapter {
37
+ /**
38
+ * Upload a file buffer and return a publicly accessible URL.
39
+ * @param buffer - File content
40
+ * @param filename - Original filename (used for MIME detection)
41
+ * @param mimeType - MIME type of the file
42
+ * @param apiKey - Provider API key
43
+ * @param signal - Abort signal
44
+ */
45
+ uploadFile(buffer: Buffer, filename: string, mimeType: string, apiKey: string, signal?: AbortSignal): Promise<FileUploadResult>;
46
+ }
47
+ /** Guess MIME type from filename extension. */
48
+ export declare function guessMimeType(filename: string): string;
49
+ /** Check if a URL points to a local/private address that cloud APIs cannot reach. */
50
+ export declare function isLocalUrl(url: string): boolean;
51
+ /**
52
+ * Resolve a local URL by uploading its content to the provider's File API.
53
+ * Public URLs are returned as-is (the LLM API can fetch them directly).
54
+ *
55
+ * @param url - The URL to resolve (may be local or public)
56
+ * @param adapter - Provider-specific upload adapter
57
+ * @param apiKey - API key for the upload
58
+ * @param signal - Optional abort signal
59
+ * @returns Public URL accessible by the LLM
60
+ */
61
+ export declare function resolveLocalMedia(url: string, adapter: FileUploadAdapter, apiKey: string, signal?: AbortSignal): Promise<string>;
62
+ /**
63
+ * Batch-resolve multiple URLs concurrently. Returns array in same order.
64
+ * Local URLs are uploaded; public URLs pass through unchanged.
65
+ * Supports concurrent uploads (up to `concurrency` limit, default 3).
66
+ * Failures throw (caller should handle).
67
+ */
68
+ export declare function resolveLocalMediaBatch(urls: string[], adapter: FileUploadAdapter, apiKey: string, signal?: AbortSignal, concurrency?: number): Promise<string[]>;
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
15
15
  import type { ProviderQuirks } from "../provider-def.js";
16
+ import type { FileUploadAdapter } from "../file-upload-service.js";
16
17
  export interface AnthropicTransportConfig {
17
18
  baseUrl: string;
18
19
  /** anthropic-version header (default "2023-06-01") */
@@ -29,6 +30,8 @@ export interface AnthropicTransportConfig {
29
30
  omitZeroTemperature?: boolean;
30
31
  /** Provider-specific quirks for conditional logic (CC/altcode parity) */
31
32
  quirks?: ProviderQuirks;
33
+ /** File upload adapter (Hub OSS relay for Anthropic). */
34
+ fileUploadAdapter?: FileUploadAdapter;
32
35
  }
33
36
  export declare class AnthropicMessagesTransport implements LLMTransport {
34
37
  private baseUrl;
@@ -39,6 +42,7 @@ export declare class AnthropicMessagesTransport implements LLMTransport {
39
42
  private maxRetries;
40
43
  private omitZeroTemperature;
41
44
  private quirks;
45
+ private fileUploadAdapter?;
42
46
  constructor(config: AnthropicTransportConfig);
43
47
  stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
44
48
  /**
@@ -21,6 +21,7 @@
21
21
  */
22
22
  import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
23
23
  import type { ProviderQuirks } from "../provider-def.js";
24
+ import type { FileUploadAdapter } from "../file-upload-service.js";
24
25
  export interface GeminiGenerateContentTransportConfig {
25
26
  /** Base URL, e.g. "https://generativelanguage.googleapis.com/v1beta" */
26
27
  baseUrl: string;
@@ -28,11 +29,14 @@ export interface GeminiGenerateContentTransportConfig {
28
29
  timeoutMs?: number;
29
30
  /** Provider-specific quirks */
30
31
  quirks?: ProviderQuirks;
32
+ /** File upload adapter for resolving local media URLs via upload instead of base64. */
33
+ fileUploadAdapter?: FileUploadAdapter;
31
34
  }
32
35
  export declare class GeminiGenerateContentTransport implements LLMTransport {
33
36
  private baseUrl;
34
37
  private timeoutMs;
35
38
  private quirks;
39
+ private fileUploadAdapter?;
36
40
  constructor(config: GeminiGenerateContentTransportConfig);
37
41
  stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
38
42
  private buildRequestBody;
@@ -1,25 +1,50 @@
1
1
  /**
2
- * Media URL Resolution — converts local/private URLs to inline base64 data URLs.
2
+ * Media URL Resolution — resolves local/private URLs for cloud LLM APIs.
3
3
  *
4
- * Cloud LLM APIs (OpenAI, Anthropic, DeepSeek) cannot fetch content from
5
- * localhost or private networks. This utility detects such URLs and resolves
6
- * them to base64 data URLs that can be sent inline.
4
+ * Cloud LLM APIs (OpenAI, Anthropic, DeepSeek, etc.) cannot fetch content
5
+ * from localhost or private networks.
6
+ *
7
+ * **Primary approach (upload-based):**
8
+ * Local URLs are fetched → uploaded to provider's File API or Aliyun OSS → public URL returned.
9
+ * This is the ONLY approach for images, video, and documents.
10
+ *
11
+ * **Audio exception (base64):**
12
+ * OpenAI's input_audio.data API field mandates base64 encoding.
13
+ * resolveMediaUrl() is retained ONLY for this case.
7
14
  *
8
15
  * URL-first design: the gateway stores media as HTTP URLs; this layer handles
9
16
  * the last-mile transformation before sending to provider APIs.
10
17
  */
18
+ import type { FileUploadAdapter } from "../file-upload-service.js";
11
19
  /** Check if a URL points to a local/private address that cloud APIs cannot reach. */
12
20
  export declare function isLocalUrl(url: string): boolean;
21
+ export interface MediaResolveContext {
22
+ /** Provider-specific upload adapter. */
23
+ uploadAdapter: FileUploadAdapter;
24
+ /** API key for the upload. */
25
+ apiKey: string;
26
+ /** Abort signal. */
27
+ signal?: AbortSignal;
28
+ }
13
29
  /**
14
- * Resolve a URL to a base64 data URL if it's a local address.
15
- * Public URLs are returned as-is (the LLM API can fetch them directly).
30
+ * Resolve a local URL by uploading to the provider's File API.
31
+ * This is the **preferred** method for all media types.
16
32
  *
17
- * Returns the original URL for non-local addresses.
18
- * Returns a `data:<mime>;base64,...` string for local addresses.
33
+ * Public URLs pass through unchanged.
34
+ * Local URLs are uploaded public URL or file_id returned.
19
35
  */
20
- export declare function resolveMediaUrl(url: string, fallbackMime?: string): Promise<string>;
36
+ export declare function resolveMediaUrlViaUpload(url: string, ctx: MediaResolveContext): Promise<string>;
37
+ /**
38
+ * Batch-resolve URLs via upload. Best-effort: failures return original URL.
39
+ */
40
+ export declare function resolveMediaUrlsViaUpload(urls: string[], ctx: MediaResolveContext): Promise<string[]>;
21
41
  /**
22
- * Batch-resolve multiple URLs. Returns array in same order.
23
- * Failures are logged and the original URL is kept (best-effort).
42
+ * Resolve local audio URL to base64 data URL.
43
+ *
44
+ * ONLY for audio — OpenAI's input_audio.data API field mandates base64 encoding.
45
+ * There is no upload alternative for audio in the OpenAI API.
46
+ *
47
+ * For images/video/documents: ALWAYS use resolveMediaUrlViaUpload() instead.
48
+ * base64 is forbidden for non-audio media per project architecture rules.
24
49
  */
25
- export declare function resolveMediaUrls(urls: string[], fallbackMime?: string): Promise<string[]>;
50
+ export declare function resolveMediaUrl(url: string, fallbackMime?: string): Promise<string>;
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import type { LLMChunk, LLMRequest, LLMTransport, FIMRequest, FIMChunk } from "../transport.js";
15
15
  import type { ProviderQuirks } from "../provider-def.js";
16
+ import type { FileUploadAdapter } from "../file-upload-service.js";
16
17
  export interface OpenAIChatTransportConfig {
17
18
  baseUrl: string;
18
19
  /** Additional headers (e.g. for specific providers) */
@@ -25,6 +26,8 @@ export interface OpenAIChatTransportConfig {
25
26
  omitZeroTemperature?: boolean;
26
27
  /** Provider-specific quirks (CC/altcode parity) */
27
28
  quirks?: ProviderQuirks;
29
+ /** File upload adapter for resolving local media URLs via upload instead of base64. */
30
+ fileUploadAdapter?: FileUploadAdapter;
28
31
  }
29
32
  export declare class OpenAIChatTransport implements LLMTransport {
30
33
  private baseUrl;
@@ -33,6 +36,7 @@ export declare class OpenAIChatTransport implements LLMTransport {
33
36
  private supportsStreamOptions;
34
37
  private omitZeroTemperature;
35
38
  private quirks;
39
+ private fileUploadAdapter?;
36
40
  private cumulativeReasoningLen;
37
41
  private cumulativeContentLen;
38
42
  constructor(config: OpenAIChatTransportConfig);
@@ -25,17 +25,20 @@
25
25
  */
26
26
  import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
27
27
  import type { ProviderQuirks } from "../provider-def.js";
28
+ import type { FileUploadAdapter } from "../file-upload-service.js";
28
29
  export interface OpenAIResponsesTransportConfig {
29
30
  baseUrl: string;
30
31
  extraHeaders?: Record<string, string>;
31
32
  timeoutMs?: number;
32
33
  quirks?: ProviderQuirks;
34
+ fileUploadAdapter?: FileUploadAdapter;
33
35
  }
34
36
  export declare class OpenAIResponsesTransport implements LLMTransport {
35
37
  private baseUrl;
36
38
  private extraHeaders;
37
39
  private timeoutMs;
38
40
  private quirks;
41
+ private fileUploadAdapter?;
39
42
  constructor(config: OpenAIResponsesTransportConfig);
40
43
  stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
41
44
  private buildRequestBody;
@@ -18,17 +18,21 @@
18
18
  */
19
19
  import type { LLMChunk, LLMRequest, LLMTransport } from "../transport.js";
20
20
  import type { ProviderQuirks } from "../provider-def.js";
21
+ import type { FileUploadAdapter } from "../file-upload-service.js";
21
22
  export interface VolcengineResponsesTransportConfig {
22
23
  baseUrl: string;
23
24
  extraHeaders?: Record<string, string>;
24
25
  timeoutMs?: number;
25
26
  quirks?: ProviderQuirks;
27
+ /** File upload adapter for resolving local media URLs via upload instead of base64. */
28
+ fileUploadAdapter?: FileUploadAdapter;
26
29
  }
27
30
  export declare class VolcengineResponsesTransport implements LLMTransport {
28
31
  private baseUrl;
29
32
  private extraHeaders;
30
33
  private timeoutMs;
31
34
  private quirks;
35
+ private fileUploadAdapter?;
32
36
  constructor(config: VolcengineResponsesTransportConfig);
33
37
  stream(request: LLMRequest, apiKey: string, signal?: AbortSignal): AsyncGenerator<LLMChunk>;
34
38
  /**
@@ -1,7 +1,14 @@
1
1
  /**
2
2
  * Skill self-learning: decides whether a completed turn should
3
3
  * trigger skill creation or improvement instructions.
4
+ *
5
+ * Guards against proliferation:
6
+ * - MAX_SKILLS_PER_PROJECT: hard cap on project-level skills
7
+ * - Dedup check: compares tool-set signature against existing skills
8
+ * - Cooldown: prevents rapid-fire creation within a session
4
9
  */
10
+ import { MAX_SKILLS_PER_PROJECT, MAX_SKILLS_GLOBAL } from "../agent/tunable-defaults.js";
11
+ export { MAX_SKILLS_PER_PROJECT, MAX_SKILLS_GLOBAL };
5
12
  export interface SkillTurnResult {
6
13
  ok: boolean;
7
14
  /** Number of tool invocations in this turn */
@@ -36,6 +43,32 @@ export interface SkillImproveInstruction {
36
43
  reason: string;
37
44
  }
38
45
  export type SkillInstruction = SkillCreateInstruction | SkillImproveInstruction;
46
+ /**
47
+ * Reset cooldown state (for testing).
48
+ */
49
+ export declare function resetSkillCreationCooldown(): void;
50
+ /**
51
+ * Check if an existing skill in skillsDir already covers the same tool set.
52
+ * Returns the name of the conflicting skill, or null if none found.
53
+ */
54
+ export declare function findDuplicateSkill(tools: string[], skillsDir: string): string | null;
55
+ /**
56
+ * Count active skills in a directory.
57
+ */
58
+ export declare function countSkillsInDir(skillsDir: string): number;
59
+ /**
60
+ * Context for proliferation checks.
61
+ */
62
+ export interface SkillCreationContext {
63
+ /** Project-level skills directory */
64
+ projectSkillsDir?: string;
65
+ /** User-level (global) skills directory */
66
+ globalSkillsDir?: string;
67
+ /** Tool names used in this turn */
68
+ tools: string[];
69
+ /** Optional suggested name */
70
+ suggestedName?: string;
71
+ }
39
72
  /**
40
73
  * Determine whether a completed turn should produce a skill instruction.
41
74
  *
@@ -44,16 +77,14 @@ export type SkillInstruction = SkillCreateInstruction | SkillImproveInstruction;
44
77
  * - It involved multi-step orchestration
45
78
  * - It used ≥3 tool calls across ≥2 distinct tools
46
79
  * - No existing skill was already applied
47
- *
48
- * An improvement is suggested when:
49
- * - The turn used an existing skill but got negative feedback
80
+ * - Cooldown has elapsed since last skill creation
81
+ * - No duplicate skill exists (same tool signature)
82
+ * - Project skill count < MAX_SKILLS_PER_PROJECT
50
83
  */
51
- export declare function shouldCreateSkill(result: SkillTurnResult): boolean;
84
+ export declare function shouldCreateSkill(result: SkillTurnResult, context?: SkillCreationContext): boolean;
52
85
  export declare function shouldImproveSkill(result: SkillTurnResult): boolean;
53
86
  /**
54
87
  * Build a skill instruction from a turn result, or null if none is warranted.
88
+ * Updates cooldown timestamp on success.
55
89
  */
56
- export declare function buildSkillInstruction(result: SkillTurnResult, context: {
57
- tools: string[];
58
- suggestedName?: string;
59
- }): SkillInstruction | null;
90
+ export declare function buildSkillInstruction(result: SkillTurnResult, context: SkillCreationContext): SkillInstruction | null;