@dugleelabs/copair 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +135 -11
- package/dist/api.js +170 -122
- package/dist/api.js.map +1 -1
- package/dist/index.js +169 -121
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/api.d.ts
CHANGED
|
@@ -81,6 +81,10 @@ declare const ProviderConfigSchema: z.ZodObject<{
|
|
|
81
81
|
}, z.core.$strip>>;
|
|
82
82
|
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
83
83
|
}, z.core.$strip>;
|
|
84
|
+
declare const SmallModelsConfigSchema: z.ZodObject<{
|
|
85
|
+
model_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
86
|
+
max_tool_calls: z.ZodOptional<z.ZodNumber>;
|
|
87
|
+
}, z.core.$strip>;
|
|
84
88
|
declare const CopairConfigSchema: z.ZodObject<{
|
|
85
89
|
version: z.ZodNumber;
|
|
86
90
|
default_model: z.ZodOptional<z.ZodString>;
|
|
@@ -172,9 +176,14 @@ declare const CopairConfigSchema: z.ZodObject<{
|
|
|
172
176
|
web_search_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
|
173
177
|
provider_timeout_ms: z.ZodDefault<z.ZodNumber>;
|
|
174
178
|
}, z.core.$strip>>;
|
|
179
|
+
small_models: z.ZodOptional<z.ZodObject<{
|
|
180
|
+
model_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
181
|
+
max_tool_calls: z.ZodOptional<z.ZodNumber>;
|
|
182
|
+
}, z.core.$strip>>;
|
|
175
183
|
}, z.core.$strip>;
|
|
176
184
|
type CopairConfig = z.infer<typeof CopairConfigSchema>;
|
|
177
185
|
type ProviderConfig = z.infer<typeof ProviderConfigSchema>;
|
|
186
|
+
type SmallModelsConfig = z.infer<typeof SmallModelsConfigSchema>;
|
|
178
187
|
|
|
179
188
|
type ProviderFactory = (config: ProviderConfig, model: string) => Provider;
|
|
180
189
|
declare class ProviderRegistry {
|
|
@@ -216,21 +225,42 @@ declare class ToolRegistry {
|
|
|
216
225
|
getAllDefinitions(): ToolDefinition[];
|
|
217
226
|
}
|
|
218
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Path-level permissions — model-agnostic.
|
|
230
|
+
* Applies regardless of which tool the model uses (read, bash cat, grep, etc.).
|
|
231
|
+
* write permission implies read.
|
|
232
|
+
*/
|
|
233
|
+
interface PathPermissions {
|
|
234
|
+
read: string[];
|
|
235
|
+
write: string[];
|
|
236
|
+
}
|
|
219
237
|
interface AllowRules {
|
|
220
238
|
/** bash entries: exact match, or prefix if the pattern ends with " *" */
|
|
221
239
|
bash: string[];
|
|
222
240
|
/**
|
|
223
241
|
* git entries: matched against the args string.
|
|
224
|
-
* Entry is the subcommand (e.g. "diff") —
|
|
225
|
-
* flags for that subcommand (e.g. "diff --cached", "diff HEAD~1").
|
|
242
|
+
* Entry is the subcommand (e.g. "diff") — covers all flags for that subcommand.
|
|
226
243
|
*/
|
|
227
244
|
git: string[];
|
|
228
245
|
/**
|
|
229
|
-
*
|
|
230
|
-
*
|
|
246
|
+
* Tool-specific read/write/edit entries (kept for backward-compat and
|
|
247
|
+
* fine-grained tool control). For multi-model setups, prefer `paths:`.
|
|
231
248
|
*/
|
|
249
|
+
read: string[];
|
|
232
250
|
write: string[];
|
|
233
251
|
edit: string[];
|
|
252
|
+
/**
|
|
253
|
+
* Path-level permissions — the preferred way to allow cross-repo access.
|
|
254
|
+
* Works regardless of which tool the model chooses to use for an operation.
|
|
255
|
+
*
|
|
256
|
+
* Example allow.yaml:
|
|
257
|
+
* paths:
|
|
258
|
+
* read:
|
|
259
|
+
* - "../../other-repo/**"
|
|
260
|
+
* write:
|
|
261
|
+
* - "../../shared-output/**"
|
|
262
|
+
*/
|
|
263
|
+
paths: PathPermissions;
|
|
234
264
|
}
|
|
235
265
|
declare class AllowList {
|
|
236
266
|
private rules;
|
|
@@ -238,11 +268,25 @@ declare class AllowList {
|
|
|
238
268
|
/**
|
|
239
269
|
* Returns true when the operation is explicitly listed and should bypass
|
|
240
270
|
* the approval prompt. Called by ApprovalGate before prompting.
|
|
271
|
+
*
|
|
272
|
+
* Check order per tool:
|
|
273
|
+
* 1. Tool-specific entries (bash:, git:, read:, write:, edit:) — fine-grained
|
|
274
|
+
* 2. Path-level entries (paths.read / paths.write) — model-agnostic
|
|
241
275
|
*/
|
|
242
276
|
matches(toolName: string, input: Record<string, unknown>): boolean;
|
|
243
277
|
private matchBash;
|
|
278
|
+
/**
|
|
279
|
+
* Path-level bash matching: extract path tokens from the command, classify
|
|
280
|
+
* as read or write intent, then check against paths.read / paths.write.
|
|
281
|
+
* All path tokens in the command must be covered for the check to pass.
|
|
282
|
+
*/
|
|
283
|
+
private matchBashByPath;
|
|
244
284
|
private matchGit;
|
|
245
285
|
private matchPath;
|
|
286
|
+
/**
|
|
287
|
+
* Check filePath against paths.read or paths.write (write implies read).
|
|
288
|
+
*/
|
|
289
|
+
private matchPathAgainstPermissions;
|
|
246
290
|
}
|
|
247
291
|
|
|
248
292
|
interface ToolInfo {
|
|
@@ -275,15 +319,27 @@ interface TokenUsage {
|
|
|
275
319
|
contextPercent?: number;
|
|
276
320
|
}
|
|
277
321
|
type ApprovalAnswer = 'allow' | 'always' | 'deny' | 'all' | 'similar';
|
|
322
|
+
/** Pre-approval diff shown at the approval prompt (before execution). */
|
|
323
|
+
interface ApprovalDiffPreview {
|
|
324
|
+
filePath: string;
|
|
325
|
+
oldContent: string | null;
|
|
326
|
+
newContent: string;
|
|
327
|
+
diffText: string;
|
|
328
|
+
}
|
|
278
329
|
interface ApprovalRequest {
|
|
279
330
|
toolName: string;
|
|
280
331
|
input: Record<string, unknown>;
|
|
281
332
|
summary: string;
|
|
282
333
|
index: number;
|
|
283
334
|
total: number;
|
|
284
|
-
diff
|
|
335
|
+
/** Pre-approval diff preview (shown before user approves). */
|
|
336
|
+
diff?: ApprovalDiffPreview | null;
|
|
285
337
|
/** Present when a bash command references a sensitive system path. */
|
|
286
338
|
warning?: string;
|
|
339
|
+
/** Present when a bash command references a path outside the project root. */
|
|
340
|
+
crossRepoBashPath?: string;
|
|
341
|
+
/** Present when a read/glob/grep targets a path outside the project root. */
|
|
342
|
+
crossRepoReadPath?: string;
|
|
287
343
|
}
|
|
288
344
|
interface AgentBridgeEvents {
|
|
289
345
|
'stream-text': (text: string) => void;
|
|
@@ -297,11 +353,22 @@ interface AgentBridgeEvents {
|
|
|
297
353
|
'approval-request': (request: ApprovalRequest, respond: (answer: ApprovalAnswer) => void) => void;
|
|
298
354
|
'diff': (diff: DiffInfo) => void;
|
|
299
355
|
'usage': (usage: TokenUsage) => void;
|
|
300
|
-
'thinking-start': () => void;
|
|
356
|
+
'thinking-start': (label?: string) => void;
|
|
301
357
|
'thinking-stop': () => void;
|
|
302
358
|
'turn-complete': () => void;
|
|
303
359
|
'error': (message: string) => void;
|
|
304
|
-
'input-request': (respond: (input: string) => void) => void;
|
|
360
|
+
'input-request': (prompt: string, respond: (input: string) => void) => void;
|
|
361
|
+
'context-limit-warning': () => void;
|
|
362
|
+
'context-limit-action': (respond: (action: 'compact' | 'abort') => void) => void;
|
|
363
|
+
'task-complete': (data: {
|
|
364
|
+
summary: string;
|
|
365
|
+
}) => void;
|
|
366
|
+
'max-turn-warning': (data: {
|
|
367
|
+
limit: number;
|
|
368
|
+
}) => void;
|
|
369
|
+
'unclear-signal': (data: {
|
|
370
|
+
message: string;
|
|
371
|
+
}) => void;
|
|
305
372
|
}
|
|
306
373
|
type EventName = keyof AgentBridgeEvents;
|
|
307
374
|
/**
|
|
@@ -335,8 +402,8 @@ declare class AgentBridge extends EventEmitter {
|
|
|
335
402
|
* input_summary is always redacted and truncated to ≤ 200 chars before
|
|
336
403
|
* writing so that raw secrets never appear in the audit log.
|
|
337
404
|
*/
|
|
338
|
-
type AuditEvent = 'session_start' | 'session_end' | 'tool_call' | 'approval' | 'denial' | 'path_block' | 'schema_rejection' | 'bash_sensitive_path';
|
|
339
|
-
type AuditOutcome = 'allowed' | 'denied' | 'error';
|
|
405
|
+
type AuditEvent = 'session_start' | 'session_end' | 'tool_call' | 'approval' | 'denial' | 'path_block' | 'schema_rejection' | 'bash_sensitive_path' | 'bash_cross_repo' | 'cross_repo_read';
|
|
406
|
+
type AuditOutcome = 'allowed' | 'denied' | 'error' | 'flagged';
|
|
340
407
|
interface AuditEntry {
|
|
341
408
|
ts: string;
|
|
342
409
|
event: AuditEvent;
|
|
@@ -386,7 +453,7 @@ declare class ApprovalGate {
|
|
|
386
453
|
* The agent never calls this. ToolExecutor calls it. The agent only
|
|
387
454
|
* sees the resulting ExecutionResult.
|
|
388
455
|
*/
|
|
389
|
-
allow(toolName: string, input: Record<string, unknown
|
|
456
|
+
allow(toolName: string, input: Record<string, unknown>, diffPreview?: ApprovalDiffPreview): Promise<boolean>;
|
|
390
457
|
/** Bridge-based approval: emit event and await response from ink UI. */
|
|
391
458
|
private bridgePrompt;
|
|
392
459
|
/** Legacy approval prompt: reads from /dev/tty directly (not stdin).
|
|
@@ -455,7 +522,15 @@ declare class PathGuard {
|
|
|
455
522
|
* @param mustExist true for read operations (file must exist); false for
|
|
456
523
|
* write/edit operations (parent dir must exist).
|
|
457
524
|
*/
|
|
458
|
-
check(rawPath: string, mustExist: boolean
|
|
525
|
+
check(rawPath: string, mustExist: boolean, opts?: {
|
|
526
|
+
skipBoundaryCheck?: boolean;
|
|
527
|
+
}): PathGuardResult;
|
|
528
|
+
/**
|
|
529
|
+
* Check whether a raw path resolves to somewhere inside the project root.
|
|
530
|
+
* Used by the tool executor to flag cross-repo references before the gate fires.
|
|
531
|
+
* Returns false on any resolution error — treat as outside.
|
|
532
|
+
*/
|
|
533
|
+
isInsideProject(rawPath: string): boolean;
|
|
459
534
|
private isDenied;
|
|
460
535
|
private isAllowed;
|
|
461
536
|
/**
|
|
@@ -655,8 +730,43 @@ declare class ConversationManager {
|
|
|
655
730
|
static fromJSONL(data: string): Message[];
|
|
656
731
|
}
|
|
657
732
|
|
|
733
|
+
interface ParsedToolCall {
|
|
734
|
+
id: string;
|
|
735
|
+
name: string;
|
|
736
|
+
arguments: string;
|
|
737
|
+
}
|
|
738
|
+
interface ToolCallFormatter {
|
|
739
|
+
readonly name: string;
|
|
740
|
+
readonly markupPattern: RegExp;
|
|
741
|
+
/** Opening tag for streaming suppression (e.g. `<tool_call>`). When set,
|
|
742
|
+
* the renderer buffers across chunks instead of applying a per-chunk regex. */
|
|
743
|
+
readonly openTag?: string;
|
|
744
|
+
readonly closeTag?: string;
|
|
745
|
+
/** When true, the streaming filter also suppresses all text that follows the
|
|
746
|
+
* first complete tool-call block in a response. Use for models that
|
|
747
|
+
* hallucinate post-tool text (e.g. "It seems there was an issue…"). */
|
|
748
|
+
readonly suppressAfterMatch?: boolean;
|
|
749
|
+
parse(text: string): {
|
|
750
|
+
toolCalls: ParsedToolCall[];
|
|
751
|
+
remainingText: string;
|
|
752
|
+
};
|
|
753
|
+
buildSystemPrompt(tools: ToolDefinition$1[]): string;
|
|
754
|
+
/** Return a minimal example tool call in this formatter's markup language. */
|
|
755
|
+
exampleCall(): string;
|
|
756
|
+
}
|
|
757
|
+
|
|
658
758
|
type FormatName = 'dsml' | 'qwen-xml' | 'fenced-block';
|
|
659
759
|
|
|
760
|
+
declare class SmallModelHarness {
|
|
761
|
+
readonly isSmallModel: boolean;
|
|
762
|
+
private config;
|
|
763
|
+
constructor(modelId: string, config?: SmallModelsConfig, forceOverride?: boolean);
|
|
764
|
+
get maxToolCalls(): number;
|
|
765
|
+
getSystemPromptAddition(): string | null;
|
|
766
|
+
getPerTurnReminder(): string | null;
|
|
767
|
+
getFormatHint(formatter: ToolCallFormatter): string | null;
|
|
768
|
+
}
|
|
769
|
+
|
|
660
770
|
interface AgentOptions {
|
|
661
771
|
systemPrompt?: string;
|
|
662
772
|
maxTokens?: number;
|
|
@@ -664,6 +774,9 @@ interface AgentOptions {
|
|
|
664
774
|
toolCallFormat?: FormatName;
|
|
665
775
|
bridge?: AgentBridge;
|
|
666
776
|
pluginManager?: PluginManager;
|
|
777
|
+
/** Fraction of maxTokens at which to warn about context limit (0–1, default 0.9). */
|
|
778
|
+
contextLimitThresholdPct?: number;
|
|
779
|
+
harness?: SmallModelHarness;
|
|
667
780
|
}
|
|
668
781
|
declare class Agent {
|
|
669
782
|
private provider;
|
|
@@ -677,6 +790,7 @@ declare class Agent {
|
|
|
677
790
|
private formatter;
|
|
678
791
|
private textFilter;
|
|
679
792
|
private pluginManager?;
|
|
793
|
+
private harness?;
|
|
680
794
|
constructor(provider: Provider, model: string, toolRegistry: ToolRegistry, executor: ToolExecutor, options?: AgentOptions);
|
|
681
795
|
get model(): string;
|
|
682
796
|
getConversation(): ConversationManager;
|
|
@@ -693,6 +807,16 @@ declare class Agent {
|
|
|
693
807
|
/** Input tokens from the last API call — reflects actual context window usage. */
|
|
694
808
|
lastInputTokens: number;
|
|
695
809
|
}>;
|
|
810
|
+
/** Prompt the user for input and return their answer (used by ask_user intercept). */
|
|
811
|
+
private collectUserAnswer;
|
|
812
|
+
/**
|
|
813
|
+
* Detect whether the model likely hit its context limit this turn.
|
|
814
|
+
* Two signals:
|
|
815
|
+
* 1. Token threshold: input tokens ≥ contextLimitThresholdPct of maxTokens
|
|
816
|
+
* 2. Truncation heuristic: text present, no tool calls, and response ends
|
|
817
|
+
* without terminal punctuation (sentence was cut off mid-stream)
|
|
818
|
+
*/
|
|
819
|
+
private detectContextLimit;
|
|
696
820
|
}
|
|
697
821
|
|
|
698
822
|
interface SessionMetadata {
|