@dugleelabs/copair 1.9.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,8 +74,8 @@ 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>>;
@@ -107,8 +107,8 @@ declare const CopairConfigSchema: z.ZodObject<{
107
107
  supports_tool_calling: z.ZodOptional<z.ZodBoolean>;
108
108
  supports_streaming: z.ZodOptional<z.ZodBoolean>;
109
109
  tool_call_format: z.ZodOptional<z.ZodEnum<{
110
- dsml: "dsml";
111
110
  "qwen-xml": "qwen-xml";
111
+ dsml: "dsml";
112
112
  "fenced-block": "fenced-block";
113
113
  }>>;
114
114
  }, z.core.$strip>>;
@@ -186,6 +186,42 @@ declare const CopairConfigSchema: z.ZodObject<{
186
186
  }>>>;
187
187
  max_tool_calls: z.ZodOptional<z.ZodNumber>;
188
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>>;
189
225
  }, z.core.$strip>;
190
226
  type CopairConfig = z.infer<typeof CopairConfigSchema>;
191
227
  type ProviderConfig = z.infer<typeof ProviderConfigSchema>;
@@ -206,9 +242,29 @@ interface ToolDefinition {
206
242
  description: string;
207
243
  inputSchema: Record<string, unknown>;
208
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
+ };
209
263
  interface ToolResult {
210
264
  content: string;
211
265
  isError?: boolean;
266
+ /** spec 029 (F-15b): overflow/truncation events for the agent to dispatch. */
267
+ events?: ToolEvent[];
212
268
  }
213
269
  interface Tool {
214
270
  definition: ToolDefinition;
@@ -375,6 +431,38 @@ interface AgentBridgeEvents {
375
431
  'unclear-signal': (data: {
376
432
  message: string;
377
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;
378
466
  }
379
467
  type EventName = keyof AgentBridgeEvents;
380
468
  /**
@@ -555,6 +643,8 @@ interface ExecutionResult {
555
643
  denied?: boolean;
556
644
  /** Actual tool execution time in ms (excludes approval prompt wait). */
557
645
  _durationMs?: number;
646
+ /** Spec 029 F-15b: declarative side-effects (overflow/truncation) the agent dispatches. */
647
+ events?: ToolEvent[];
558
648
  }
559
649
  /**
560
650
  * Executes tools on behalf of the agent loop.
@@ -740,7 +830,37 @@ interface ParsedToolCall {
740
830
  id: string;
741
831
  name: string;
742
832
  arguments: string;
833
+ /** Provider-specific metadata (e.g. native tool-call IDs). Passed through opaquely. */
834
+ metadata?: Record<string, unknown>;
743
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
+ };
744
864
  interface ToolCallFormatter {
745
865
  readonly name: string;
746
866
  readonly markupPattern: RegExp;
@@ -759,13 +879,20 @@ interface ToolCallFormatter {
759
879
  buildSystemPrompt(tools: ToolDefinition$1[]): string;
760
880
  /** Return a minimal example tool call in this formatter's markup language. */
761
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;
762
888
  }
763
889
 
764
890
  type FormatName = 'dsml' | 'qwen-xml' | 'fenced-block';
765
891
 
766
892
  declare class SmallModelHarness {
767
893
  readonly isSmallModel: boolean;
768
- private config;
894
+ private readonly modelId;
895
+ private readonly config;
769
896
  constructor(modelId: string, config?: SmallModelsConfig, forceOverride?: boolean);
770
897
  get maxToolCalls(): number;
771
898
  getSystemPromptAddition(): string | null;
@@ -797,6 +924,7 @@ declare class Agent {
797
924
  private textFilter;
798
925
  private pluginManager?;
799
926
  private harness?;
927
+ private loopGuard;
800
928
  constructor(provider: Provider, model: string, toolRegistry: ToolRegistry, executor: ToolExecutor, options?: AgentOptions);
801
929
  get model(): string;
802
930
  getConversation(): ConversationManager;
@@ -813,6 +941,13 @@ declare class Agent {
813
941
  /** Input tokens from the last API call — reflects actual context window usage. */
814
942
  lastInputTokens: number;
815
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;
816
951
  /** Prompt the user for input and return their answer (used by ask_user intercept). */
817
952
  private collectUserAnswer;
818
953
  /**