@davidorex/pi-jit-agents 0.14.6

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 (50) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/README.md +45 -0
  3. package/dist/agent-spec.d.ts +24 -0
  4. package/dist/agent-spec.d.ts.map +1 -0
  5. package/dist/agent-spec.js +126 -0
  6. package/dist/agent-spec.js.map +1 -0
  7. package/dist/agent-trace-sdk.d.ts +42 -0
  8. package/dist/agent-trace-sdk.d.ts.map +1 -0
  9. package/dist/agent-trace-sdk.js +177 -0
  10. package/dist/agent-trace-sdk.js.map +1 -0
  11. package/dist/compile.d.ts +17 -0
  12. package/dist/compile.d.ts.map +1 -0
  13. package/dist/compile.js +118 -0
  14. package/dist/compile.js.map +1 -0
  15. package/dist/errors.d.ts +36 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +56 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/index.d.ts +22 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +18 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/introspect.d.ts +17 -0
  24. package/dist/introspect.d.ts.map +1 -0
  25. package/dist/introspect.js +22 -0
  26. package/dist/introspect.js.map +1 -0
  27. package/dist/jit-runtime.d.ts +106 -0
  28. package/dist/jit-runtime.d.ts.map +1 -0
  29. package/dist/jit-runtime.js +583 -0
  30. package/dist/jit-runtime.js.map +1 -0
  31. package/dist/template.d.ts +36 -0
  32. package/dist/template.d.ts.map +1 -0
  33. package/dist/template.js +78 -0
  34. package/dist/template.js.map +1 -0
  35. package/dist/trace-redactor.d.ts +43 -0
  36. package/dist/trace-redactor.d.ts.map +1 -0
  37. package/dist/trace-redactor.js +173 -0
  38. package/dist/trace-redactor.js.map +1 -0
  39. package/dist/trace-writer.d.ts +13 -0
  40. package/dist/trace-writer.d.ts.map +1 -0
  41. package/dist/trace-writer.js +112 -0
  42. package/dist/trace-writer.js.map +1 -0
  43. package/dist/types.d.ts +185 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +2 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +71 -0
  48. package/schemas/agent-trace.schema.json +191 -0
  49. package/schemas/trace-config.schema.json +58 -0
  50. package/schemas/verdict.schema.json +14 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Nunjucks template environment and rendering.
3
+ *
4
+ * Implements D3 (no .pi/ reads) for the template discovery side. The template
5
+ * search mirrors the agent-spec three-tier pattern:
6
+ * 1. {cwd}/.project/templates/
7
+ * 2. {userDir ?? ~/.pi/agent/templates/}
8
+ * 3. {builtinDir} (only when supplied)
9
+ *
10
+ * Autoescape is disabled (agents render markdown, not HTML). throwOnUndefined
11
+ * is disabled (templates may reference optional context without error).
12
+ *
13
+ * `${{ }}` workflow expressions are protected from Nunjucks interpretation
14
+ * by escape-and-restore. This preserves the invariant that workflow-level
15
+ * expression resolution happens at workflow dispatch time, not at agent
16
+ * compile time.
17
+ */
18
+ import fs from "node:fs";
19
+ import os from "node:os";
20
+ import path from "node:path";
21
+ import nunjucks from "nunjucks";
22
+ /**
23
+ * Create a Nunjucks environment with three-tier template discovery.
24
+ *
25
+ * Returns a no-op loader environment (plain strings pass through) when no
26
+ * tier directory exists. This is not an error — an agent with an entirely
27
+ * inline prompt uses no templates at all.
28
+ */
29
+ export function createTemplateEnv(ctx) {
30
+ const projectDir = path.join(ctx.cwd, ".project", "templates");
31
+ const userDir = ctx.userDir ?? path.join(os.homedir(), ".pi", "agent", "templates");
32
+ const searchPaths = [];
33
+ if (fs.existsSync(projectDir))
34
+ searchPaths.push(projectDir);
35
+ if (fs.existsSync(userDir))
36
+ searchPaths.push(userDir);
37
+ if (ctx.builtinDir && fs.existsSync(ctx.builtinDir))
38
+ searchPaths.push(ctx.builtinDir);
39
+ const loader = searchPaths.length > 0 ? new nunjucks.FileSystemLoader(searchPaths) : undefined;
40
+ return new nunjucks.Environment(loader, {
41
+ autoescape: false,
42
+ throwOnUndefined: false,
43
+ });
44
+ }
45
+ /** Sentinel used to protect `${{ }}` workflow expressions from Nunjucks rendering. */
46
+ const WORKFLOW_EXPR_PLACEHOLDER = "\x00__PI_WORKFLOW_EXPR__";
47
+ function escapeRegExp(s) {
48
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
49
+ }
50
+ /**
51
+ * Render a template string through Nunjucks.
52
+ *
53
+ * Protects `${{ }}` workflow expressions from Nunjucks by escaping them
54
+ * before rendering and restoring them after.
55
+ */
56
+ export function renderTemplate(env, templateStr, context) {
57
+ const escaped = templateStr.replace(/\$\{\{/g, WORKFLOW_EXPR_PLACEHOLDER);
58
+ const rendered = env.renderString(escaped, context);
59
+ return rendered.replace(new RegExp(escapeRegExp(WORKFLOW_EXPR_PLACEHOLDER), "g"), "${{");
60
+ }
61
+ /**
62
+ * Render a named template file through Nunjucks.
63
+ *
64
+ * The template name is resolved by the environment's FileSystemLoader through
65
+ * the configured three-tier search.
66
+ *
67
+ * Absolute paths bypass the loader and are read directly. This supports
68
+ * fully-resolved AgentSpec fields where systemPromptTemplate / taskPromptTemplate
69
+ * carry absolute paths after loadAgent (per D1).
70
+ */
71
+ export function renderTemplateFile(env, templateName, context) {
72
+ if (path.isAbsolute(templateName)) {
73
+ const content = fs.readFileSync(templateName, "utf-8");
74
+ return renderTemplate(env, content, context);
75
+ }
76
+ return env.render(templateName, context);
77
+ }
78
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,QAAQ,MAAM,UAAU,CAAC;AAWhC;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACxD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAEpF,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5D,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtD,IAAI,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAEtF,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE/F,OAAO,IAAI,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE;QACvC,UAAU,EAAE,KAAK;QACjB,gBAAgB,EAAE,KAAK;KACvB,CAAC,CAAC;AACJ,CAAC;AAED,sFAAsF;AACtF,MAAM,yBAAyB,GAAG,0BAA0B,CAAC;AAE7D,SAAS,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC7B,GAAyB,EACzB,WAAmB,EACnB,OAAgC;IAEhC,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,EAAE,yBAAyB,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpD,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,YAAY,CAAC,yBAAyB,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;AAC1F,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CACjC,GAAyB,EACzB,YAAoB,EACpB,OAAgC;IAEhC,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACvD,OAAO,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,43 @@
1
+ export interface RedactionPattern {
2
+ name: string;
3
+ regex: RegExp;
4
+ replacement: string;
5
+ }
6
+ export interface RedactionConfig {
7
+ /** Additional patterns from project-extension config, applied after BUILTIN_PATTERNS in order. */
8
+ patterns?: RedactionPattern[];
9
+ }
10
+ /**
11
+ * Exhaustive built-in pattern set as of the audit. Order matters: more specific shapes
12
+ * (e.g. `sk-or-` OpenRouter prefix) come before less specific (e.g. generic `sk-` OpenAI)
13
+ * to keep replacement labels accurate where prefixes overlap.
14
+ */
15
+ export declare const BUILTIN_PATTERNS: ReadonlyArray<RedactionPattern>;
16
+ /**
17
+ * Apply all redaction patterns to a string and return the redacted result.
18
+ * Builtin patterns run first, then any additional patterns from `config.patterns` in order.
19
+ * Idempotent: running the function on its own output produces an identical string, because
20
+ * the replacement tokens (e.g. `[REDACTED:...]`) do not match any builtin pattern shape.
21
+ */
22
+ export declare function redactSensitiveData(text: string, config?: RedactionConfig): string;
23
+ /**
24
+ * Apply redaction to an LLM AssistantMessage's content array. Preserves message structure
25
+ * (returns same shape as input). For each content item:
26
+ * - if it has a string `text` field, that field is redacted.
27
+ * - if it has an array `content` field, recurse.
28
+ * - otherwise, the item is passed through unchanged.
29
+ *
30
+ * Type erased via `T extends { content: unknown[] }` so the helper composes with any
31
+ * pi-ai content shape (text blocks, tool calls, thinking blocks, structured content).
32
+ */
33
+ export declare function redactLlmResponse<T extends {
34
+ content: unknown[];
35
+ }>(message: T, config?: RedactionConfig): T;
36
+ /**
37
+ * Load redaction patterns from a project-extension config file.
38
+ * Expected shape: `{ patterns: [{ name, regex: "<string-pattern>", replacement?, domain? }] }`.
39
+ * Compiles each `regex` string to a RegExp with the `g` flag.
40
+ * Throws if the file does not exist, parses to invalid JSON, or contains malformed entries.
41
+ */
42
+ export declare function loadProjectRedactionConfig(configPath: string): RedactionPattern[];
43
+ //# sourceMappingURL=trace-redactor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-redactor.d.ts","sourceRoot":"","sources":["../src/trace-redactor.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC/B,kGAAkG;IAClG,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,CAkD5D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,CAYlF;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,OAAO,EAAE,CAAA;CAAE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,CAAC,CAG3G;AA0BD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB,EAAE,CA8CjF"}
@@ -0,0 +1,173 @@
1
+ // trace-redactor: credential / sensitive-data redaction for monitor-classify trace records.
2
+ //
3
+ // Per DEC-0005 and the canonical-compliance audit for issue-023, trace records produced by
4
+ // the monitor-classify capture path may contain rendered LLM prompts and full assistant
5
+ // responses. Those payloads can carry credentials echoed by users (pasted API keys, OAuth
6
+ // tokens, secrets in code samples). Pi-mono's SessionManager performs no redaction; this
7
+ // module is the pre-write filter that aims to strip well-known sensitive shapes BEFORE
8
+ // trace records are persisted.
9
+ //
10
+ // Scope intent (not a guarantee):
11
+ // - Match known credential surface shapes via the BUILTIN_PATTERNS set.
12
+ // - Allow per-project augmentation via .workflows/monitors/<name>/trace-config.json.
13
+ // - Preserve LLM message structure while redacting text fields recursively.
14
+ // Limits:
15
+ // - Pattern-based redaction is best-effort; it cannot detect arbitrary opaque secrets.
16
+ // - Operators remain responsible for reviewing trace output before sharing externally.
17
+ import { existsSync, readFileSync } from "node:fs";
18
+ /**
19
+ * Exhaustive built-in pattern set as of the audit. Order matters: more specific shapes
20
+ * (e.g. `sk-or-` OpenRouter prefix) come before less specific (e.g. generic `sk-` OpenAI)
21
+ * to keep replacement labels accurate where prefixes overlap.
22
+ */
23
+ export const BUILTIN_PATTERNS = [
24
+ { name: "anthropic_api_key", regex: /sk-ant-[a-zA-Z0-9_-]{20,}/g, replacement: "[REDACTED:anthropic_api_key]" },
25
+ { name: "openrouter_api_key", regex: /sk-or-[a-zA-Z0-9_-]{20,}/g, replacement: "[REDACTED:openrouter_api_key]" },
26
+ { name: "openai_api_key", regex: /sk-(?:proj-)?[a-zA-Z0-9_-]{20,}/g, replacement: "[REDACTED:openai_api_key]" },
27
+ { name: "google_api_key", regex: /AIza[0-9A-Za-z\-_]{35}/g, replacement: "[REDACTED:google_api_key]" },
28
+ { name: "aws_access_key", regex: /AKIA[0-9A-Z]{16}/g, replacement: "[REDACTED:aws_access_key]" },
29
+ {
30
+ name: "aws_secret_key",
31
+ // Matches the `aws_secret_access_key` field name followed by `=` or `:` separator and a
32
+ // secret value, optionally wrapped in single or double quotes. Body uses `+` (1-or-more)
33
+ // rather than `{40}` so we tolerate the canonical 40-char AWS shape AND test fixtures /
34
+ // generated keys that diverge from that exact length. Case-insensitive to cover env-var
35
+ // uppercasing (AWS_SECRET_ACCESS_KEY).
36
+ regex: /aws_secret_access_key\s*[=:]\s*["']?[A-Za-z0-9/+=]{16,}["']?/gi,
37
+ replacement: "[REDACTED:aws_secret_key]",
38
+ },
39
+ {
40
+ name: "gcp_service_account",
41
+ regex: /"type":\s*"service_account"[\s\S]*?"private_key":\s*"[^"]*"/g,
42
+ replacement: "[REDACTED:gcp_service_account]",
43
+ },
44
+ { name: "github_token_ghp", regex: /ghp_[a-zA-Z0-9_]{36,}/g, replacement: "[REDACTED:github_token_ghp]" },
45
+ { name: "github_token_gho", regex: /gho_[a-zA-Z0-9_]{36,}/g, replacement: "[REDACTED:github_token_gho]" },
46
+ { name: "github_token_ghs", regex: /ghs_[a-zA-Z0-9_]{36,}/g, replacement: "[REDACTED:github_token_ghs]" },
47
+ { name: "github_token_ghu", regex: /ghu_[a-zA-Z0-9_]{36,}/g, replacement: "[REDACTED:github_token_ghu]" },
48
+ { name: "jwt", regex: /eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, replacement: "[REDACTED:jwt]" },
49
+ {
50
+ name: "bearer_token",
51
+ regex: /Authorization:\s*Bearer\s+([a-zA-Z0-9_\-.]+)/gi,
52
+ replacement: "Authorization: Bearer [REDACTED:bearer_token]",
53
+ },
54
+ {
55
+ name: "ssh_private_key",
56
+ // PEM marker shape: `-----BEGIN <ALGO> PRIVATE KEY-----\n<base64 body, possibly multi-line>\n-----END <ALGO> PRIVATE KEY-----`.
57
+ // The previous form omitted the closing `-----` of the BEGIN line and used `[^-]*` for
58
+ // the body — neither admitted a real PEM block (the very next chars after `KEY` are
59
+ // `-----`, hyphens). `[\s\S]*?` is non-greedy match-anything-including-newlines, which
60
+ // stops at the first `-----END...KEY-----` sequence. Algorithm token kept optional so
61
+ // PEM blocks without an explicit ALGO (rare, OpenSSH) still match.
62
+ regex: /-----BEGIN\s+(?:RSA|DSA|EC|OPENSSH|PGP|ENCRYPTED)?\s*PRIVATE\s+KEY-----[\s\S]*?-----END\s+(?:RSA|DSA|EC|OPENSSH|PGP|ENCRYPTED)?\s*PRIVATE\s+KEY-----/g,
63
+ replacement: "[REDACTED:ssh_private_key]",
64
+ },
65
+ { name: "postgres_conn_string", regex: /postgres:\/\/[^:]+:[^@]+@[^/]+\/\S+/g, replacement: "postgres://[REDACTED]" },
66
+ { name: "mysql_conn_string", regex: /mysql:\/\/[^:]+:[^@]+@[^/]+\/\S+/g, replacement: "mysql://[REDACTED]" },
67
+ {
68
+ name: "mongodb_conn_string",
69
+ regex: /mongodb(?:\+srv)?:\/\/[^:]+:[^@]+@[^/]+/g,
70
+ replacement: "mongodb://[REDACTED]",
71
+ },
72
+ ];
73
+ /**
74
+ * Apply all redaction patterns to a string and return the redacted result.
75
+ * Builtin patterns run first, then any additional patterns from `config.patterns` in order.
76
+ * Idempotent: running the function on its own output produces an identical string, because
77
+ * the replacement tokens (e.g. `[REDACTED:...]`) do not match any builtin pattern shape.
78
+ */
79
+ export function redactSensitiveData(text, config) {
80
+ if (typeof text !== "string" || text.length === 0)
81
+ return text;
82
+ let out = text;
83
+ for (const pattern of BUILTIN_PATTERNS) {
84
+ out = out.replace(pattern.regex, pattern.replacement);
85
+ }
86
+ if (config?.patterns) {
87
+ for (const pattern of config.patterns) {
88
+ out = out.replace(pattern.regex, pattern.replacement);
89
+ }
90
+ }
91
+ return out;
92
+ }
93
+ /**
94
+ * Apply redaction to an LLM AssistantMessage's content array. Preserves message structure
95
+ * (returns same shape as input). For each content item:
96
+ * - if it has a string `text` field, that field is redacted.
97
+ * - if it has an array `content` field, recurse.
98
+ * - otherwise, the item is passed through unchanged.
99
+ *
100
+ * Type erased via `T extends { content: unknown[] }` so the helper composes with any
101
+ * pi-ai content shape (text blocks, tool calls, thinking blocks, structured content).
102
+ */
103
+ export function redactLlmResponse(message, config) {
104
+ const redactedContent = message.content.map((item) => redactContentItem(item, config));
105
+ return { ...message, content: redactedContent };
106
+ }
107
+ function redactContentItem(item, config) {
108
+ if (item === null || typeof item !== "object")
109
+ return item;
110
+ const obj = item;
111
+ const result = { ...obj };
112
+ if (typeof obj.text === "string") {
113
+ result.text = redactSensitiveData(obj.text, config);
114
+ }
115
+ if (Array.isArray(obj.content)) {
116
+ result.content = obj.content.map((nested) => redactContentItem(nested, config));
117
+ }
118
+ return result;
119
+ }
120
+ /**
121
+ * Load redaction patterns from a project-extension config file.
122
+ * Expected shape: `{ patterns: [{ name, regex: "<string-pattern>", replacement?, domain? }] }`.
123
+ * Compiles each `regex` string to a RegExp with the `g` flag.
124
+ * Throws if the file does not exist, parses to invalid JSON, or contains malformed entries.
125
+ */
126
+ export function loadProjectRedactionConfig(configPath) {
127
+ if (!existsSync(configPath)) {
128
+ throw new Error(`trace redaction config not found: ${configPath}`);
129
+ }
130
+ const raw = readFileSync(configPath, "utf8");
131
+ let parsed;
132
+ try {
133
+ parsed = JSON.parse(raw);
134
+ }
135
+ catch (err) {
136
+ throw new Error(`trace redaction config is not valid JSON: ${configPath}: ${err.message}`);
137
+ }
138
+ if (!parsed || typeof parsed !== "object") {
139
+ throw new Error(`trace redaction config must be a JSON object: ${configPath}`);
140
+ }
141
+ const patterns = parsed.patterns;
142
+ if (patterns === undefined)
143
+ return [];
144
+ if (!Array.isArray(patterns)) {
145
+ throw new Error(`trace redaction config 'patterns' must be an array: ${configPath}`);
146
+ }
147
+ const out = [];
148
+ for (let i = 0; i < patterns.length; i++) {
149
+ const entry = patterns[i];
150
+ if (!entry || typeof entry !== "object") {
151
+ throw new Error(`trace redaction config patterns[${i}] must be an object: ${configPath}`);
152
+ }
153
+ if (typeof entry.name !== "string" || entry.name.length === 0) {
154
+ throw new Error(`trace redaction config patterns[${i}].name must be a non-empty string: ${configPath}`);
155
+ }
156
+ if (typeof entry.regex !== "string" || entry.regex.length === 0) {
157
+ throw new Error(`trace redaction config patterns[${i}].regex must be a non-empty string: ${configPath}`);
158
+ }
159
+ let compiled;
160
+ try {
161
+ compiled = new RegExp(entry.regex, "g");
162
+ }
163
+ catch (err) {
164
+ throw new Error(`trace redaction config patterns[${i}].regex did not compile: ${configPath}: ${err.message}`);
165
+ }
166
+ const replacement = typeof entry.replacement === "string" && entry.replacement.length > 0
167
+ ? entry.replacement
168
+ : `[REDACTED:${entry.name}]`;
169
+ out.push({ name: entry.name, regex: compiled, replacement });
170
+ }
171
+ return out;
172
+ }
173
+ //# sourceMappingURL=trace-redactor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-redactor.js","sourceRoot":"","sources":["../src/trace-redactor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface WriteTraceOptions {
2
+ /** Path to the JSONL file. Will be created if it does not exist. Parent directories will be created. */
3
+ tracePath: string;
4
+ /** Maximum file size in bytes before rotation overflow split. Default 500MB. */
5
+ maxFileSizeBytes?: number;
6
+ /** Skip schema validation. Default false. ONLY for tests. */
7
+ skipValidation?: boolean;
8
+ }
9
+ /** Append a single TraceEntry to the JSONL file. Validates against the schema. Atomic per-entry write via flock. */
10
+ export declare function writeAgentTrace(entry: unknown, options: WriteTraceOptions): void;
11
+ /** Mint a date-rotated trace file path: <baseDir>/<YYYY-MM-DD>.jsonl. Caller passes baseDir; helper handles date math. */
12
+ export declare function dateRotatedPath(baseDir: string, date?: Date): string;
13
+ //# sourceMappingURL=trace-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-writer.d.ts","sourceRoot":"","sources":["../src/trace-writer.ts"],"names":[],"mappings":"AA+CA,MAAM,WAAW,iBAAiB;IACjC,wGAAwG;IACxG,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,oHAAoH;AACpH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,GAAG,IAAI,CA2BhF;AAkCD,0HAA0H;AAC1H,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,CAMpE"}
@@ -0,0 +1,112 @@
1
+ // trace-writer: JSONL persistence layer for the monitor-classify trace capture pipeline (issue-023).
2
+ //
3
+ // Layered above trace-redactor (T2) and below the executeAgent integration point (T5/T6),
4
+ // this module accepts an already-redacted TraceEntry, validates it against
5
+ // packages/pi-jit-agents/schemas/agent-trace.schema.json, and atomically appends one JSONL
6
+ // line to the configured trace file. Per DEC-0005 (push-write divergence from pi-mono's
7
+ // pull/replay model) entries are written immediately at the moment of occurrence inside
8
+ // executeAgent rather than reconstructed at session close, so each append must be self-
9
+ // validating and crash-safe — a partial write or interleaved write from a concurrent process
10
+ // would corrupt the JSONL invariant (one valid JSON document per line).
11
+ //
12
+ // Crash-safety strategy:
13
+ // - JSONL append uses fs.appendFileSync, mirroring pi-coding-agent's session-manager pattern.
14
+ // - Cross-process safety uses proper-lockfile (already present in the workspace via
15
+ // pi-coding-agent's transitive dependency tree). Node 23.x exposes node:fs flockSync as
16
+ // `undefined` in the version this repo targets, so the userspace lockfile approach is
17
+ // the working option; the lock is held only for the duration of the append.
18
+ // - Schema validation reuses validateFromFile from @davidorex/pi-project/schema-validator
19
+ // so the AJV runtime, error format, and ESM/CJS interop shim live in one place.
20
+ //
21
+ // Size-rotation strategy:
22
+ // - Before append, stat the target. If it exceeds maxFileSizeBytes (default 500 MB), the
23
+ // writer mints the next available `<base>-NNN.jsonl` split file and appends there. The
24
+ // prior file is left as a closed split. Date-based rotation is exposed separately via
25
+ // dateRotatedPath() so callers compose the two without coupling.
26
+ import { appendFileSync, existsSync, mkdirSync, statSync } from "node:fs";
27
+ import path from "node:path";
28
+ import { fileURLToPath } from "node:url";
29
+ import { validateFromFile } from "@davidorex/pi-project/schema-validator";
30
+ // proper-lockfile is CommonJS — under Node16 module resolution + ESM consumer the default
31
+ // import resolves to the module namespace, so lockSync hangs off the default export.
32
+ import _properLockfile from "proper-lockfile";
33
+ // CJS interop: depending on bundler / tsconfig, the default may be the namespace itself or
34
+ // a wrapping `{ default: ns }`. Resolve once at module load.
35
+ const properLockfile = (_properLockfile.default ??
36
+ _properLockfile);
37
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
38
+ // In dist the module sits at packages/pi-jit-agents/dist/trace-writer.js, in src at
39
+ // packages/pi-jit-agents/src/trace-writer.ts. Both resolve to ../schemas relative to the
40
+ // module file, since schemas/ ships at the package root.
41
+ const TRACE_SCHEMA_PATH = path.resolve(moduleDir, "..", "schemas", "agent-trace.schema.json");
42
+ const DEFAULT_MAX_FILE_SIZE_BYTES = 500_000_000;
43
+ /** Append a single TraceEntry to the JSONL file. Validates against the schema. Atomic per-entry write via flock. */
44
+ export function writeAgentTrace(entry, options) {
45
+ const maxSize = options.maxFileSizeBytes ?? DEFAULT_MAX_FILE_SIZE_BYTES;
46
+ if (!options.skipValidation) {
47
+ // Throws ValidationError on schema mismatch; descriptive message includes instancePath + reason.
48
+ validateFromFile(TRACE_SCHEMA_PATH, entry, "agent-trace entry");
49
+ }
50
+ const targetPath = resolveSplitTarget(options.tracePath, maxSize);
51
+ // Ensure parent dir exists. mkdirSync is idempotent with recursive: true.
52
+ mkdirSync(path.dirname(targetPath), { recursive: true });
53
+ // Acquire the per-file lock. Fail-fast on contention: proper-lockfile defaults to a
54
+ // short retry window which we override with retries: 0 so a contended write surfaces
55
+ // rather than blocking the dispatch loop indefinitely. The lock requires the target
56
+ // path to exist; create an empty file first if it doesn't.
57
+ if (!existsSync(targetPath)) {
58
+ appendFileSync(targetPath, "");
59
+ }
60
+ const release = properLockfile.lockSync(targetPath, { retries: 0, stale: 5_000, realpath: false });
61
+ try {
62
+ appendFileSync(targetPath, `${JSON.stringify(entry)}\n`);
63
+ }
64
+ finally {
65
+ release();
66
+ }
67
+ }
68
+ /**
69
+ * Resolve the actual file path to write to, honoring the size-overflow split policy.
70
+ * If the base path is missing or under maxSize, returns it unchanged. Otherwise scans
71
+ * for the next available `<base>-NNN.jsonl` split.
72
+ */
73
+ function resolveSplitTarget(basePath, maxSize) {
74
+ if (!existsSync(basePath))
75
+ return basePath;
76
+ let size;
77
+ try {
78
+ size = statSync(basePath).size;
79
+ }
80
+ catch {
81
+ return basePath;
82
+ }
83
+ if (size < maxSize)
84
+ return basePath;
85
+ const ext = path.extname(basePath); // typically ".jsonl"
86
+ const stem = basePath.slice(0, basePath.length - ext.length);
87
+ for (let i = 1; i <= 9999; i++) {
88
+ const suffix = String(i).padStart(3, "0");
89
+ const candidate = `${stem}-${suffix}${ext}`;
90
+ if (!existsSync(candidate))
91
+ return candidate;
92
+ let candSize;
93
+ try {
94
+ candSize = statSync(candidate).size;
95
+ }
96
+ catch {
97
+ return candidate;
98
+ }
99
+ if (candSize < maxSize)
100
+ return candidate;
101
+ }
102
+ throw new Error(`trace-writer: exhausted split suffix range (-001..-9999) for ${basePath}`);
103
+ }
104
+ /** Mint a date-rotated trace file path: <baseDir>/<YYYY-MM-DD>.jsonl. Caller passes baseDir; helper handles date math. */
105
+ export function dateRotatedPath(baseDir, date) {
106
+ const d = date ?? new Date();
107
+ const yyyy = d.getUTCFullYear().toString().padStart(4, "0");
108
+ const mm = (d.getUTCMonth() + 1).toString().padStart(2, "0");
109
+ const dd = d.getUTCDate().toString().padStart(2, "0");
110
+ return path.join(baseDir, `${yyyy}-${mm}-${dd}.jsonl`);
111
+ }
112
+ //# sourceMappingURL=trace-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-writer.js","sourceRoot":"","sources":["../src/trace-writer.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,EAAE;AACF,0FAA0F;AAC1F,2EAA2E;AAC3E,2FAA2F;AAC3F,wFAAwF;AACxF,wFAAwF;AACxF,wFAAwF;AACxF,6FAA6F;AAC7F,wEAAwE;AACxE,EAAE;AACF,yBAAyB;AACzB,gGAAgG;AAChG,sFAAsF;AACtF,4FAA4F;AAC5F,0FAA0F;AAC1F,gFAAgF;AAChF,4FAA4F;AAC5F,oFAAoF;AACpF,EAAE;AACF,0BAA0B;AAC1B,2FAA2F;AAC3F,2FAA2F;AAC3F,0FAA0F;AAC1F,qEAAqE;AAErE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,0FAA0F;AAC1F,qFAAqF;AACrF,OAAO,eAAe,MAAM,iBAAiB,CAAC;AAE9C,2FAA2F;AAC3F,6DAA6D;AAC7D,MAAM,cAAc,GAAG,CAAE,eAAmE,CAAC,OAAO;IACnG,eAAe,CAA2B,CAAC;AAE5C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/D,oFAAoF;AACpF,yFAAyF;AACzF,yDAAyD;AACzD,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,yBAAyB,CAAC,CAAC;AAE9F,MAAM,2BAA2B,GAAG,WAAW,CAAC;AAWhD,oHAAoH;AACpH,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,OAA0B;IACzE,MAAM,OAAO,GAAG,OAAO,CAAC,gBAAgB,IAAI,2BAA2B,CAAC;IAExE,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAC7B,iGAAiG;QACjG,gBAAgB,CAAC,iBAAiB,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAElE,0EAA0E;IAC1E,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzD,oFAAoF;IACpF,qFAAqF;IACrF,oFAAoF;IACpF,2DAA2D;IAC3D,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7B,cAAc,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IACnG,IAAI,CAAC;QACJ,cAAc,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1D,CAAC;YAAS,CAAC;QACV,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAAC,QAAgB,EAAE,OAAe;IAC5D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC3C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACJ,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,QAAQ,CAAC;IACjB,CAAC;IACD,IAAI,IAAI,GAAG,OAAO;QAAE,OAAO,QAAQ,CAAC;IAEpC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,qBAAqB;IACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,GAAG,IAAI,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;QAC5C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC7C,IAAI,QAAgB,CAAC;QACrB,IAAI,CAAC;YACJ,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,IAAI,QAAQ,GAAG,OAAO;YAAE,OAAO,SAAS,CAAC;IAC1C,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gEAAgE,QAAQ,EAAE,CAAC,CAAC;AAC7F,CAAC;AAED,0HAA0H;AAC1H,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,IAAW;IAC3D,MAAM,CAAC,GAAG,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5D,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC7D,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Type surface for pi-jit-agents.
3
+ *
4
+ * Implements the jit-agents-spec.md §2 boundary contract: four public surfaces
5
+ * (load, compile, execute, introspect) with typed inputs and outputs.
6
+ */
7
+ import type { Api, AssistantMessage, Model } from "@mariozechner/pi-ai";
8
+ import type nunjucks from "nunjucks";
9
+ /**
10
+ * A loaded agent specification.
11
+ *
12
+ * Per D1 (jit-agents-spec.md §4), every path field is fully resolved to an
13
+ * absolute filesystem path by the time loadAgent returns. Consumers never see
14
+ * relative paths and never need to know which directory the spec was loaded
15
+ * from to interpret its references.
16
+ */
17
+ export interface AgentSpec {
18
+ name: string;
19
+ description?: string;
20
+ role?: string;
21
+ model?: string;
22
+ thinking?: string;
23
+ tools?: string[];
24
+ extensions?: string[];
25
+ skills?: string[];
26
+ /** Inline system prompt text (alternative to systemPromptTemplate). */
27
+ systemPrompt?: string;
28
+ /** Absolute path to a Nunjucks template file for the system prompt. */
29
+ systemPromptTemplate?: string;
30
+ /** Absolute path to a Nunjucks template file for the task prompt. */
31
+ taskPromptTemplate?: string;
32
+ /** Inline task prompt text (alternative to taskPromptTemplate). */
33
+ taskPrompt?: string;
34
+ inputSchema?: Record<string, unknown>;
35
+ outputFormat?: "json" | "text";
36
+ /**
37
+ * Absolute path to a JSON Schema file. May also be a `block:<name>` sentinel
38
+ * that resolves to `.project/schemas/<name>.schema.json` at compile time
39
+ * against the invocation cwd.
40
+ */
41
+ outputSchema?: string;
42
+ contextBlocks?: string[];
43
+ /**
44
+ * Directory the spec was loaded from. Internal use — exposed on the type
45
+ * for tier-aware operations but never relied on by consumers directly.
46
+ */
47
+ readonly loadedFrom: string;
48
+ }
49
+ /**
50
+ * Options for loadAgent / createAgentLoader.
51
+ *
52
+ * Per D7 (jit-agents-spec.md §4), the loader searches three tiers in order:
53
+ * 1. {cwd}/.project/agents/
54
+ * 2. {userDir ?? ~/.pi/agent/agents/}
55
+ * 3. {builtinDir} (only when supplied)
56
+ *
57
+ * Per D3, .pi/agents/ is NOT searched — that path is Pi platform territory.
58
+ */
59
+ export interface LoadContext {
60
+ /** Project root. Used to resolve the project-level tier and as base for block reads. */
61
+ cwd: string;
62
+ /** Optional consumer-supplied builtin agents directory. When absent, builtin tier is skipped. */
63
+ builtinDir?: string;
64
+ /** Test hook to override the user tier. Defaults to `~/.pi/agent/agents/`. */
65
+ userDir?: string;
66
+ }
67
+ /**
68
+ * Options for compileAgent.
69
+ */
70
+ export interface CompileContext {
71
+ /** Nunjucks environment from createTemplateEnv — used to render template references. */
72
+ env: nunjucks.Environment;
73
+ /** Resolved input for template rendering. Object fields become top-level template variables. */
74
+ input: unknown;
75
+ /** Project root. Used for `.project/` block reads during contextBlocks injection. */
76
+ cwd: string;
77
+ }
78
+ /**
79
+ * A compiled agent ready for dispatch.
80
+ */
81
+ export interface CompiledAgent {
82
+ /** The originating spec (fully resolved paths). */
83
+ spec: AgentSpec;
84
+ /** Rendered system prompt, if the spec declared one. */
85
+ systemPrompt?: string;
86
+ /** Rendered task prompt. Required — dispatch has nothing to send without it. */
87
+ taskPrompt: string;
88
+ /** Model spec copied from the agent spec for dispatch convenience. */
89
+ model?: string;
90
+ /** Absolute output schema path (copied from spec — already resolved). */
91
+ outputSchema?: string;
92
+ /**
93
+ * Resolved per-collector context values, keyed by the contextBlock name
94
+ * (e.g. "conventions"), populated when contextBlocks are read from `.project/`
95
+ * during compilation. Surfaced for trace capture (issue-023 T5/T6) so the
96
+ * push-write trace stream can emit one `context_collection` entry per
97
+ * resolved block. Empty object when the spec declares no contextBlocks.
98
+ *
99
+ * The values stored here are the raw (unwrapped) block payloads — distinct
100
+ * from the anti-injection-wrapped strings that the templates see under the
101
+ * `_<name>` key. Trace consumers want the structured value for downstream
102
+ * inspection, not the rendered string.
103
+ */
104
+ contextValues: Record<string, unknown>;
105
+ }
106
+ /**
107
+ * Dispatch-time context for executeAgent.
108
+ */
109
+ export interface DispatchContext {
110
+ /** Resolved pi-ai Model instance from the consumer's model registry. */
111
+ model: Model<Api>;
112
+ /** API auth — apiKey and headers from the consumer's model registry. */
113
+ auth: JitAgentAuth;
114
+ /** Max tokens for the LLM call. Defaults to 1024. */
115
+ maxTokens?: number;
116
+ /** Abort signal for cancellation. */
117
+ signal?: AbortSignal;
118
+ /**
119
+ * Trace destination for the monitor-classify trace capture pipeline (issue-023).
120
+ * - `undefined` → use the default resolution (env var or null fallback).
121
+ * - `null` → tracing explicitly disabled; no JSONL is written.
122
+ * - `string` → absolute path to the JSONL trace file the writer should append to.
123
+ *
124
+ * Per DEC-0005 the trace stream is push-write (emitted at the moment of occurrence
125
+ * inside executeAgent), divergent from pi-mono's pull/replay session model.
126
+ */
127
+ tracePath?: string | null;
128
+ /**
129
+ * Optional path to a project-extension trace redaction config
130
+ * (`.workflows/monitors/<name>/trace-config.json` shape). When set,
131
+ * `loadProjectRedactionConfig` is invoked once per executeAgent call and
132
+ * the resulting custom patterns are layered atop `BUILTIN_PATTERNS` for
133
+ * every redacted field. When unset / null, only the builtin pattern set
134
+ * applies. Independent of `tracePath` — config loading is a no-op when
135
+ * tracing itself is disabled.
136
+ */
137
+ redactionConfigPath?: string | null;
138
+ /**
139
+ * Optional monitor name for stamping `session_start.monitorName`. The
140
+ * `executeAgent` boundary itself does not know whether its caller is a
141
+ * monitor classify path or a workflow agent step — the monitor wrapper
142
+ * (T6's `classifyViaAgent`) sets this when dispatching as a classifier.
143
+ * `null` / absent for non-monitor traces.
144
+ */
145
+ monitorName?: string | null;
146
+ }
147
+ /**
148
+ * API credentials for an LLM call.
149
+ */
150
+ export interface JitAgentAuth {
151
+ apiKey: string;
152
+ headers: Record<string, string>;
153
+ }
154
+ /**
155
+ * Result of an executeAgent invocation.
156
+ */
157
+ export interface JitAgentResult {
158
+ /** Parsed output — tool_call arguments if schema-bound, extracted text otherwise. */
159
+ output: unknown;
160
+ /** Raw AssistantMessage for debugging and tracing. */
161
+ raw: AssistantMessage;
162
+ /** Token usage and cost from the call. */
163
+ usage: {
164
+ input: number;
165
+ output: number;
166
+ cacheRead: number;
167
+ cacheWrite: number;
168
+ cost: number;
169
+ };
170
+ }
171
+ /**
172
+ * Projection of an AgentSpec for introspection.
173
+ *
174
+ * Used by SDK query surfaces to answer "what does this agent accept/produce"
175
+ * without dispatching it. Internal fields (loadedFrom) are not exposed.
176
+ */
177
+ export interface AgentContract {
178
+ name: string;
179
+ role?: string;
180
+ inputSchema?: Record<string, unknown>;
181
+ contextBlocks?: string[];
182
+ outputFormat?: "json" | "text";
183
+ outputSchema?: string;
184
+ }
185
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map