@taodigital/agents 0.0.0-stage → 1.2.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 (76) hide show
  1. package/README.md +99 -2
  2. package/dist/api-test-agent.d.ts +126 -0
  3. package/dist/api-test-agent.js +267 -0
  4. package/dist/artifact-intel-agent.d.ts +11 -0
  5. package/dist/artifact-intel-agent.js +152 -0
  6. package/dist/coverage-gap-agent.d.ts +25 -0
  7. package/dist/coverage-gap-agent.js +269 -0
  8. package/dist/coverage-map-agent.d.ts +15 -0
  9. package/dist/coverage-map-agent.js +255 -0
  10. package/dist/crawl-diff-agent.d.ts +27 -0
  11. package/dist/crawl-diff-agent.js +412 -0
  12. package/dist/data-agent.d.ts +101 -0
  13. package/dist/data-agent.js +2284 -0
  14. package/dist/document-agent.d.ts +10 -0
  15. package/dist/document-agent.js +32 -0
  16. package/dist/enhancement-agent.d.ts +48 -0
  17. package/dist/enhancement-agent.js +342 -0
  18. package/dist/field-detector-agent.d.ts +35 -0
  19. package/dist/field-detector-agent.js +220 -0
  20. package/dist/flow-agent.d.ts +130 -0
  21. package/dist/flow-agent.js +169 -0
  22. package/dist/github-agent.d.ts +18 -0
  23. package/dist/github-agent.js +39 -0
  24. package/dist/github-write-agent.d.ts +67 -0
  25. package/dist/github-write-agent.js +249 -0
  26. package/dist/grouping-agent.d.ts +18 -0
  27. package/dist/grouping-agent.js +338 -0
  28. package/dist/healing-agent.d.ts +73 -0
  29. package/dist/healing-agent.js +137 -0
  30. package/dist/index.d.ts +36 -0
  31. package/dist/index.js +67 -0
  32. package/dist/integration-test-agent.d.ts +118 -0
  33. package/dist/integration-test-agent.js +165 -0
  34. package/dist/label-assignment-agent.d.ts +15 -0
  35. package/dist/label-assignment-agent.js +97 -0
  36. package/dist/llm-config.d.ts +38 -0
  37. package/dist/llm-config.js +287 -0
  38. package/dist/llm-mock.d.ts +77 -0
  39. package/dist/llm-mock.js +192 -0
  40. package/dist/llm.d.ts +58 -0
  41. package/dist/llm.js +438 -0
  42. package/dist/nlp-agent.d.ts +208 -0
  43. package/dist/nlp-agent.js +340 -0
  44. package/dist/orchestrator.d.ts +285 -0
  45. package/dist/orchestrator.js +141 -0
  46. package/dist/plan-agent.d.ts +4 -0
  47. package/dist/plan-agent.js +200 -0
  48. package/dist/repo-scan-agent.d.ts +189 -0
  49. package/dist/repo-scan-agent.js +2032 -0
  50. package/dist/requirements-agent.d.ts +59 -0
  51. package/dist/requirements-agent.js +641 -0
  52. package/dist/scenario-agent.d.ts +20 -0
  53. package/dist/scenario-agent.js +123 -0
  54. package/dist/script-agent.d.ts +447 -0
  55. package/dist/script-agent.js +11813 -0
  56. package/dist/security-test-agent.d.ts +111 -0
  57. package/dist/security-test-agent.js +141 -0
  58. package/dist/skill-file-agent.d.ts +264 -0
  59. package/dist/skill-file-agent.js +3470 -0
  60. package/dist/step-coverage.d.ts +46 -0
  61. package/dist/step-coverage.js +288 -0
  62. package/dist/step-utils.d.ts +2 -0
  63. package/dist/step-utils.js +62 -0
  64. package/dist/test-case-agent.d.ts +206 -0
  65. package/dist/test-case-agent.js +2141 -0
  66. package/dist/test-import-agent.d.ts +148 -0
  67. package/dist/test-import-agent.js +3235 -0
  68. package/dist/test-script-agent.d.ts +16 -0
  69. package/dist/test-script-agent.js +48 -0
  70. package/dist/token-pricing.d.ts +14 -0
  71. package/dist/token-pricing.js +62 -0
  72. package/dist/types.d.ts +232 -0
  73. package/dist/types.js +7 -0
  74. package/dist/visual-agent.d.ts +114 -0
  75. package/dist/visual-agent.js +261 -0
  76. package/package.json +26 -4
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ /**
3
+ * Mock / record / replay layer for the LLM choke points in llm.ts.
4
+ *
5
+ * Purpose: let agent flows (routing, dedup, persistence, token accounting) run
6
+ * deterministically in CI without LLM spend. See docs/120-AGENT-E2E-HARNESS-PLAN.md.
7
+ *
8
+ * Env flags
9
+ * ZETA_LLM_MOCK '1' | 'replay' → replay fixtures (fallback if no fixture)
10
+ * 'record' → replay when a fixture exists, otherwise call
11
+ * the real provider and save the response
12
+ * ZETA_LLM_MOCK_DIR fixture directory (default: <cwd>/eval/fixtures/llm)
13
+ * ZETA_LLM_MOCK_FAIL '429' | '503' | 'malformed-json' | 'empty' → failure injection
14
+ *
15
+ * This module intentionally does NOT import llm.ts (avoids a circular import);
16
+ * llm.ts turns a `{ kind: 'error' }` outcome into a sanitized LLMProviderError.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.resetLlmStats = resetLlmStats;
20
+ exports.snapshotLlmStats = snapshotLlmStats;
21
+ exports.recordLlmCall = recordLlmCall;
22
+ exports.getMockMode = getMockMode;
23
+ exports.fixtureDir = fixtureDir;
24
+ exports.agentId = agentId;
25
+ exports.mockKey = mockKey;
26
+ exports.loadFixture = loadFixture;
27
+ exports.saveFixture = saveFixture;
28
+ exports.resolveMock = resolveMock;
29
+ const node_crypto_1 = require("node:crypto");
30
+ const node_fs_1 = require("node:fs");
31
+ const node_path_1 = require("node:path");
32
+ let stats = { calls: 0, promptTokens: 0, completionTokens: 0, estimatedCostUsd: 0, mockKeys: {} };
33
+ function resetLlmStats() {
34
+ stats = { calls: 0, promptTokens: 0, completionTokens: 0, estimatedCostUsd: 0, mockKeys: {} };
35
+ }
36
+ function snapshotLlmStats() {
37
+ return { ...stats, mockKeys: { ...stats.mockKeys } };
38
+ }
39
+ function recordLlmCall(usage, key, source) {
40
+ stats.calls += 1;
41
+ stats.promptTokens += usage?.promptTokens ?? 0;
42
+ stats.completionTokens += usage?.completionTokens ?? 0;
43
+ stats.estimatedCostUsd += usage?.estimatedCostUsd ?? 0;
44
+ if (key)
45
+ stats.mockKeys[key] = source ?? 'real';
46
+ }
47
+ let bannerShown = false;
48
+ function getMockMode() {
49
+ const raw = (process.env.ZETA_LLM_MOCK ?? '').trim().toLowerCase();
50
+ if (!raw || raw === '0' || raw === 'false' || raw === 'off')
51
+ return 'off';
52
+ if (process.env.NODE_ENV === 'production') {
53
+ throw new Error('[llm-mock] ZETA_LLM_MOCK is not allowed when NODE_ENV=production.');
54
+ }
55
+ if (!bannerShown) {
56
+ bannerShown = true;
57
+ console.warn(`[llm-mock] ⚠ LLM MOCK ACTIVE (mode=${raw === 'record' ? 'record' : 'replay'}) — no real provider calls in replay mode.`);
58
+ }
59
+ return raw === 'record' ? 'record' : 'replay';
60
+ }
61
+ function fixtureDir() {
62
+ return process.env.ZETA_LLM_MOCK_DIR ?? (0, node_path_1.join)(process.cwd(), 'eval', 'fixtures', 'llm');
63
+ }
64
+ function lastSystemText(system) {
65
+ if (typeof system === 'string')
66
+ return system;
67
+ return system.length ? system[system.length - 1].text : '';
68
+ }
69
+ function slug(s, max = 40) {
70
+ return s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, max) || 'x';
71
+ }
72
+ /**
73
+ * Stable agent/pass identifier derived from the pass-specific (last) system block.
74
+ * e.g. "…ZeTa Test Standard v2.0 Pass 3: Security…" → "pass-3-security"
75
+ * Falls back to a short hash of the block's first line so unknown agents still get a key.
76
+ */
77
+ function agentId(system) {
78
+ const text = lastSystemText(system);
79
+ const m = text.match(/\bPass\s+(\d+)\s*[:—-]?\s*([A-Za-z0-9/ ()&-]{0,30})/);
80
+ if (m)
81
+ return `pass-${m[1]}-${slug(m[2], 24)}`.replace(/-$/, '');
82
+ const firstLine = text.split('\n').find((l) => l.trim()) ?? '';
83
+ return `agent-${slug(firstLine, 24)}-${shortHash(firstLine)}`;
84
+ }
85
+ function shortHash(s) {
86
+ return (0, node_crypto_1.createHash)('sha1').update(s).digest('hex').slice(0, 8);
87
+ }
88
+ /**
89
+ * Key = <agent/pass id>__<screen slug or head-of-prompt hash>.
90
+ * Keys deliberately avoid hashing the full prompt so wording tweaks to prompts
91
+ * don't invalidate every fixture; only a different agent or screen changes the key.
92
+ */
93
+ function mockKey(system, user, kind = 'text') {
94
+ const screenLine = user.match(/^Screen:\s*(.+?)\s*(?:\(|$)/m)?.[1];
95
+ const scope = screenLine ? slug(screenLine, 40) : `h-${shortHash(user.slice(0, 200))}`;
96
+ return `${kind === 'vision' ? 'vision-' : ''}${agentId(system)}__${scope}`;
97
+ }
98
+ function estimateTokens(s) {
99
+ return Math.max(1, Math.ceil(s.length / 4));
100
+ }
101
+ function buildUsage(system, user, text, partial) {
102
+ const sysText = typeof system === 'string' ? system : system.map((b) => b.text).join('\n');
103
+ const promptTokens = partial?.promptTokens ?? estimateTokens(sysText + user);
104
+ const completionTokens = partial?.completionTokens ?? estimateTokens(text);
105
+ return {
106
+ provider: partial?.provider ?? 'mock',
107
+ model: partial?.model ?? 'mock-llm',
108
+ promptTokens,
109
+ completionTokens,
110
+ cacheReadTokens: partial?.cacheReadTokens ?? 0,
111
+ cacheWriteTokens: partial?.cacheWriteTokens ?? 0,
112
+ totalTokens: promptTokens + completionTokens,
113
+ estimatedCostUsd: 0,
114
+ };
115
+ }
116
+ /** Minimal schema-valid output so unknown prompts never crash a flow. */
117
+ function fallbackText(system, user, schema) {
118
+ if (schema)
119
+ return '{}';
120
+ const sys = typeof system === 'string' ? system : system.map((b) => b.text).join('\n');
121
+ if (/JSON array/i.test(sys)) {
122
+ const id = agentId(system);
123
+ return JSON.stringify([
124
+ {
125
+ title: `Mock fallback — ${id} — produces a valid case`,
126
+ kind: 'FUNCTIONAL',
127
+ priority: 'MEDIUM',
128
+ techniqueOfRecord: 'equivalence-partition',
129
+ preconditions: 'Application is reachable.',
130
+ expectedResult: 'The screen responds with the documented result.',
131
+ steps: ['Navigate to the screen under test', 'Observe the rendered page'],
132
+ groundedOn: [],
133
+ gherkin: 'Given the screen is open\nWhen the user views it\nThen it renders',
134
+ tags: ['mock-fallback'],
135
+ },
136
+ ]);
137
+ }
138
+ if (/JSON/i.test(sys))
139
+ return '{}';
140
+ return 'MOCK RESPONSE';
141
+ }
142
+ function injectedFailure(system, user) {
143
+ const mode = (process.env.ZETA_LLM_MOCK_FAIL ?? '').trim().toLowerCase();
144
+ if (!mode)
145
+ return null;
146
+ if (mode === '429')
147
+ return { kind: 'error', status: 429 };
148
+ if (mode === '503')
149
+ return { kind: 'error', status: 503 };
150
+ if (mode === 'malformed-json') {
151
+ const text = '[{"title": "truncated case", "kind": "FUNCTIONAL", "steps": ["a", ';
152
+ return { kind: 'result', source: 'injected', res: { text, usage: buildUsage(system, user, text) } };
153
+ }
154
+ if (mode === 'empty') {
155
+ return { kind: 'result', source: 'injected', res: { text: '', usage: buildUsage(system, user, '') } };
156
+ }
157
+ return null;
158
+ }
159
+ function fixturePath(key) {
160
+ return (0, node_path_1.join)(fixtureDir(), `${key}.json`);
161
+ }
162
+ function loadFixture(key) {
163
+ const p = fixturePath(key);
164
+ if (!(0, node_fs_1.existsSync)(p))
165
+ return null;
166
+ try {
167
+ return JSON.parse((0, node_fs_1.readFileSync)(p, 'utf8'));
168
+ }
169
+ catch (e) {
170
+ throw new Error(`[llm-mock] fixture ${p} is not valid JSON: ${e instanceof Error ? e.message : e}`);
171
+ }
172
+ }
173
+ function saveFixture(key, res) {
174
+ (0, node_fs_1.mkdirSync)(fixtureDir(), { recursive: true });
175
+ const body = { key, text: res.text, usage: res.usage, recordedAt: new Date().toISOString() };
176
+ (0, node_fs_1.writeFileSync)(fixturePath(key), JSON.stringify(body, null, 2) + '\n');
177
+ }
178
+ /** Decide how to answer a call while mocking is on. Never performs a network call itself. */
179
+ function resolveMock(mode, system, user, opts = {}) {
180
+ const injected = injectedFailure(system, user);
181
+ if (injected)
182
+ return injected;
183
+ const key = mockKey(system, user, opts.kind);
184
+ const fixture = loadFixture(key);
185
+ if (fixture) {
186
+ return { kind: 'result', source: 'fixture', res: { text: fixture.text, usage: buildUsage(system, user, fixture.text, fixture.usage) } };
187
+ }
188
+ if (mode === 'record')
189
+ return { kind: 'miss' };
190
+ const text = fallbackText(system, user, opts.schema);
191
+ return { kind: 'result', source: 'fallback', res: { text, usage: buildUsage(system, user, text) } };
192
+ }
package/dist/llm.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Multi-provider LLM module.
3
+ *
4
+ * Providers using their own SDK: Anthropic.
5
+ * Providers via OpenAI-compatible API (single openai package): OpenAI, Gemini,
6
+ * Grok (xAI), OpenRouter, Ollama (local), Nvidia NIM.
7
+ *
8
+ * Config is resolved per-tenant only (set in Workspace → Settings → AI Provider).
9
+ * No platform-level API key fallback — every workspace must configure its own provider.
10
+ */
11
+ import type { LLMUsage } from '@taodigital/core';
12
+ export type LLMProvider = 'anthropic' | 'openai' | 'gemini' | 'grok' | 'openrouter' | 'ollama' | 'nvidia' | 'groq' | 'mistral' | 'deepseek' | 'perplexity' | 'togetherai' | 'bedrock' | 'vertex' | 'azure';
13
+ export interface LLMConfig {
14
+ provider: LLMProvider;
15
+ model: string;
16
+ apiKey?: string;
17
+ baseUrl?: string;
18
+ }
19
+ export interface AskOptions {
20
+ temperature?: number;
21
+ topP?: number;
22
+ seed?: number;
23
+ }
24
+ export declare function deterministicSeed(input: string): number;
25
+ export declare const DEFAULT_MODELS: Record<LLMProvider, string>;
26
+ export interface ImageInput {
27
+ base64: string;
28
+ mediaType: string;
29
+ }
30
+ export interface AskResult {
31
+ text: string;
32
+ usage: LLMUsage;
33
+ }
34
+ /**
35
+ * Thrown in place of a raw provider SDK error. Provider error messages
36
+ * sometimes echo back a snippet of the request/prompt content (e.g. a
37
+ * content-policy rejection quoting the offending text), which may include a
38
+ * customer's crawled screen content or other sensitive data - safe to log
39
+ * server-side, not safe to return verbatim to whoever's looking at the API
40
+ * response. sanitizeProviderError() below preserves the actionable signal
41
+ * (rate limited vs. bad auth vs. bad request) without the raw text.
42
+ */
43
+ export declare class LLMProviderError extends Error {
44
+ /** True when the error is not transient and retrying will not help. */
45
+ readonly nonRetryable: boolean;
46
+ constructor(message?: string, nonRetryable?: boolean);
47
+ }
48
+ export declare function sanitizeProviderError(e: unknown): LLMProviderError;
49
+ /** Mock-aware entry point (see llm-mock.ts). With ZETA_LLM_MOCK unset this is a pass-through. */
50
+ export declare function askTrackedWithImages(system: string, user: string, images: ImageInput[], llmCfg?: LLMConfig, options?: AskOptions): Promise<AskResult>;
51
+ export declare function askWithImages(system: string, user: string, images: ImageInput[], llmCfg?: LLMConfig): Promise<string>;
52
+ export type SystemBlock = {
53
+ text: string;
54
+ cache?: boolean;
55
+ };
56
+ /** Mock-aware entry point (see llm-mock.ts). With ZETA_LLM_MOCK unset this is a pass-through. */
57
+ export declare function askTracked(system: string | SystemBlock[], user: string, llmCfg?: LLMConfig, maxTokens?: number, schema?: any, options?: AskOptions): Promise<AskResult>;
58
+ export declare function ask(system: string, user: string, llmCfg?: LLMConfig, maxTokens?: number): Promise<string>;