@dugleelabs/copair 1.8.0 → 1.10.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 CHANGED
@@ -74,15 +74,18 @@ declare const ProviderConfigSchema: z.ZodObject<{
74
74
  supports_tool_calling: z.ZodOptional<z.ZodBoolean>;
75
75
  supports_streaming: z.ZodOptional<z.ZodBoolean>;
76
76
  tool_call_format: z.ZodOptional<z.ZodEnum<{
77
- dsml: "dsml";
78
77
  "qwen-xml": "qwen-xml";
78
+ dsml: "dsml";
79
79
  "fenced-block": "fenced-block";
80
80
  }>>;
81
81
  }, z.core.$strip>>;
82
82
  timeout_ms: z.ZodOptional<z.ZodNumber>;
83
83
  }, z.core.$strip>;
84
84
  declare const SmallModelsConfigSchema: z.ZodObject<{
85
- model_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
85
+ tier_overrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
86
+ small: "small";
87
+ large: "large";
88
+ }>>>;
86
89
  max_tool_calls: z.ZodOptional<z.ZodNumber>;
87
90
  }, z.core.$strip>;
88
91
  declare const CopairConfigSchema: z.ZodObject<{
@@ -104,8 +107,8 @@ declare const CopairConfigSchema: z.ZodObject<{
104
107
  supports_tool_calling: z.ZodOptional<z.ZodBoolean>;
105
108
  supports_streaming: z.ZodOptional<z.ZodBoolean>;
106
109
  tool_call_format: z.ZodOptional<z.ZodEnum<{
107
- dsml: "dsml";
108
110
  "qwen-xml": "qwen-xml";
111
+ dsml: "dsml";
109
112
  "fenced-block": "fenced-block";
110
113
  }>>;
111
114
  }, z.core.$strip>>;
@@ -177,9 +180,48 @@ declare const CopairConfigSchema: z.ZodObject<{
177
180
  provider_timeout_ms: z.ZodDefault<z.ZodNumber>;
178
181
  }, z.core.$strip>>;
179
182
  small_models: z.ZodOptional<z.ZodObject<{
180
- model_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
183
+ tier_overrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
184
+ small: "small";
185
+ large: "large";
186
+ }>>>;
181
187
  max_tool_calls: z.ZodOptional<z.ZodNumber>;
182
188
  }, z.core.$strip>>;
189
+ model_overrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
190
+ tier: z.ZodOptional<z.ZodEnum<{
191
+ small: "small";
192
+ large: "large";
193
+ }>>;
194
+ context_window: z.ZodOptional<z.ZodNumber>;
195
+ max_tokens: z.ZodOptional<z.ZodNumber>;
196
+ native_tool_calling: z.ZodOptional<z.ZodEnum<{
197
+ reliable: "reliable";
198
+ unreliable: "unreliable";
199
+ none: "none";
200
+ }>>;
201
+ preferred_format: z.ZodOptional<z.ZodEnum<{
202
+ "qwen-xml": "qwen-xml";
203
+ dsml: "dsml";
204
+ "fenced-block": "fenced-block";
205
+ native: "native";
206
+ }>>;
207
+ recommended_harness: z.ZodOptional<z.ZodObject<{
208
+ enable_small_model_harness: z.ZodOptional<z.ZodBoolean>;
209
+ max_turns: z.ZodOptional<z.ZodNumber>;
210
+ max_tool_calls: z.ZodOptional<z.ZodNumber>;
211
+ inject_format_reminder_every_turn: z.ZodOptional<z.ZodBoolean>;
212
+ }, z.core.$strip>>;
213
+ }, z.core.$strip>>>;
214
+ tools: z.ZodOptional<z.ZodObject<{
215
+ read: z.ZodOptional<z.ZodObject<{
216
+ overflow_lines: z.ZodOptional<z.ZodNumber>;
217
+ }, z.core.$strip>>;
218
+ bash: z.ZodOptional<z.ZodObject<{
219
+ overflow_tokens: z.ZodOptional<z.ZodNumber>;
220
+ }, z.core.$strip>>;
221
+ grep: z.ZodOptional<z.ZodObject<{
222
+ default_max_results: z.ZodOptional<z.ZodNumber>;
223
+ }, z.core.$strip>>;
224
+ }, z.core.$strip>>;
183
225
  }, z.core.$strip>;
184
226
  type CopairConfig = z.infer<typeof CopairConfigSchema>;
185
227
  type ProviderConfig = z.infer<typeof ProviderConfigSchema>;
@@ -200,9 +242,29 @@ interface ToolDefinition {
200
242
  description: string;
201
243
  inputSchema: Record<string, unknown>;
202
244
  }
245
+ /**
246
+ * spec 029 (F-15b): declarative side-effects a tool surfaces to the agent loop,
247
+ * which dispatches each to the matching `Renderer.show*` method. Keeps tools
248
+ * renderer-free; additive (tools emitting no events are unaffected).
249
+ */
250
+ type ToolEvent = {
251
+ kind: 'bash_truncated';
252
+ label: 'stdout' | 'stderr';
253
+ originalTokens: number;
254
+ } | {
255
+ kind: 'read_overflow';
256
+ filePath: string;
257
+ lineCount: number;
258
+ } | {
259
+ kind: 'grep_overflow';
260
+ pattern: string;
261
+ maxResults: number;
262
+ };
203
263
  interface ToolResult {
204
264
  content: string;
205
265
  isError?: boolean;
266
+ /** spec 029 (F-15b): overflow/truncation events for the agent to dispatch. */
267
+ events?: ToolEvent[];
206
268
  }
207
269
  interface Tool {
208
270
  definition: ToolDefinition;
@@ -369,6 +431,38 @@ interface AgentBridgeEvents {
369
431
  'unclear-signal': (data: {
370
432
  message: string;
371
433
  }) => void;
434
+ /** Spec 029 F-13: loop guard nudged the model after 2 identical tool repeats. */
435
+ 'loop-nudge': (data: {
436
+ message: string;
437
+ }) => void;
438
+ /** Spec 029 F-13: loop guard halted the agent turn after 3 identical tool repeats. */
439
+ 'loop-halt': (data: {
440
+ reason: string;
441
+ }) => void;
442
+ /** Spec 029 F-14: format-repair retry fired after a parseStrict failure. */
443
+ 'format-repair': (data: {
444
+ specific_issue: string;
445
+ }) => void;
446
+ /** Spec 029 F-14: format-repair retries exhausted; agent turn breaks. */
447
+ 'format-repair-exhausted': (data: {
448
+ specific_issue: string;
449
+ message: string;
450
+ }) => void;
451
+ /** Spec 029 F-15b: bash stdout/stderr was head+tail truncated by the overflow helper. */
452
+ 'bash-truncated': (data: {
453
+ label: 'stdout' | 'stderr';
454
+ originalTokens: number;
455
+ }) => void;
456
+ /** Spec 029 F-15b: `read` refused to surface a large file without an explicit `limit`. */
457
+ 'read-overflow': (data: {
458
+ filePath: string;
459
+ lineCount: number;
460
+ }) => void;
461
+ /** Spec 029 F-15b: `grep` capped at `max_results` with at least one more match available. */
462
+ 'grep-overflow': (data: {
463
+ pattern: string;
464
+ maxResults: number;
465
+ }) => void;
372
466
  }
373
467
  type EventName = keyof AgentBridgeEvents;
374
468
  /**
@@ -549,6 +643,8 @@ interface ExecutionResult {
549
643
  denied?: boolean;
550
644
  /** Actual tool execution time in ms (excludes approval prompt wait). */
551
645
  _durationMs?: number;
646
+ /** Spec 029 F-15b: declarative side-effects (overflow/truncation) the agent dispatches. */
647
+ events?: ToolEvent[];
552
648
  }
553
649
  /**
554
650
  * Executes tools on behalf of the agent loop.
@@ -734,7 +830,37 @@ interface ParsedToolCall {
734
830
  id: string;
735
831
  name: string;
736
832
  arguments: string;
833
+ /** Provider-specific metadata (e.g. native tool-call IDs). Passed through opaquely. */
834
+ metadata?: Record<string, unknown>;
737
835
  }
836
+ /**
837
+ * spec 029 (F-14): structured parse error returned by `parseStrict`. The
838
+ * `specific_issue` enum drives the repair-message template and the renderer's
839
+ * format-repair event.
840
+ */
841
+ interface ParseError {
842
+ kind: 'parse';
843
+ /** Human-readable error message — surfaced to the model in the repair prompt. */
844
+ message: string;
845
+ /** A canonical example of valid markup for this formatter (≈formatter.exampleCall()). */
846
+ expected_format_example: string;
847
+ /** The part of the model's output that failed to parse, ≤200 chars. */
848
+ offending_substring: string;
849
+ specific_issue: 'unknown_tool' | 'bad_arg_type' | 'unclosed_tag' | 'invalid_json' | 'other';
850
+ }
851
+ /**
852
+ * spec 029 (F-14): non-throwing parse result. Success carries the same shape as
853
+ * legacy `parse(text)` so call sites can swap in `parseStrict` without
854
+ * remapping fields.
855
+ */
856
+ type ParseResult = {
857
+ ok: true;
858
+ toolCalls: ParsedToolCall[];
859
+ remainingText: string;
860
+ } | {
861
+ ok: false;
862
+ error: ParseError;
863
+ };
738
864
  interface ToolCallFormatter {
739
865
  readonly name: string;
740
866
  readonly markupPattern: RegExp;
@@ -753,13 +879,20 @@ interface ToolCallFormatter {
753
879
  buildSystemPrompt(tools: ToolDefinition$1[]): string;
754
880
  /** Return a minimal example tool call in this formatter's markup language. */
755
881
  exampleCall(): string;
882
+ /**
883
+ * spec 029 (F-14): non-throwing variant returning a structured error on parse
884
+ * failure. Optional — third-party formatters without it degrade through
885
+ * `parseWithStrictFallback`; the built-in formatters implement it natively.
886
+ */
887
+ parseStrict?(text: string): ParseResult;
756
888
  }
757
889
 
758
890
  type FormatName = 'dsml' | 'qwen-xml' | 'fenced-block';
759
891
 
760
892
  declare class SmallModelHarness {
761
893
  readonly isSmallModel: boolean;
762
- private config;
894
+ private readonly modelId;
895
+ private readonly config;
763
896
  constructor(modelId: string, config?: SmallModelsConfig, forceOverride?: boolean);
764
897
  get maxToolCalls(): number;
765
898
  getSystemPromptAddition(): string | null;
@@ -791,6 +924,7 @@ declare class Agent {
791
924
  private textFilter;
792
925
  private pluginManager?;
793
926
  private harness?;
927
+ private loopGuard;
794
928
  constructor(provider: Provider, model: string, toolRegistry: ToolRegistry, executor: ToolExecutor, options?: AgentOptions);
795
929
  get model(): string;
796
930
  getConversation(): ConversationManager;
@@ -807,6 +941,13 @@ declare class Agent {
807
941
  /** Input tokens from the last API call — reflects actual context window usage. */
808
942
  lastInputTokens: number;
809
943
  }>;
944
+ /**
945
+ * spec 029 (F-14): wrap a single provider streaming call so it's callable
946
+ * from both the outer iteration loop and the inner format-repair retry loop.
947
+ * Resets the streaming markup filter so `suppressAfterMatch` formatters scope
948
+ * to one response.
949
+ */
950
+ private streamOnce;
810
951
  /** Prompt the user for input and return their answer (used by ask_user intercept). */
811
952
  private collectUserAnswer;
812
953
  /**