@pikku/inspector 0.12.60 → 0.12.61
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/CHANGELOG.md +301 -0
- package/OPTIMIZATION-PLAN.md +19 -19
- package/dist/add/add-auth.js +1 -1
- package/dist/add/add-channel.d.ts +1 -1
- package/dist/add/add-cli.js +5 -0
- package/dist/add/add-functions.js +10 -1
- package/dist/add/add-http-route.js +18 -18
- package/dist/add/add-keyed-wiring.d.ts +2 -0
- package/dist/add/add-keyed-wiring.js +3 -1
- package/dist/add/add-personas.js +4 -1
- package/dist/add/add-secret.js +1 -0
- package/dist/add/add-variable.js +1 -0
- package/dist/add/add-wire-remote-addon.js +2 -1
- package/dist/add/add-workflow-graph.js +63 -6
- package/dist/add/add-workflow.d.ts +1 -1
- package/dist/error-codes.d.ts +3 -1
- package/dist/error-codes.js +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/inspector.js +12 -2
- package/dist/types.d.ts +25 -21
- package/dist/utils/annotate-http-route-auth.js +2 -1
- package/dist/utils/check-secret-sinks.js +2 -1
- package/dist/utils/compute-required-schemas.d.ts +1 -1
- package/dist/utils/contract-hashes.d.ts +2 -2
- package/dist/utils/contract-hashes.js +1 -1
- package/dist/utils/extract-function-name.js +1 -1
- package/dist/utils/extract-services.d.ts +1 -1
- package/dist/utils/extract-surface-usage.d.ts +29 -0
- package/dist/utils/extract-surface-usage.js +97 -0
- package/dist/utils/filter-inspector-state.js +53 -16
- package/dist/utils/filter-utils.d.ts +1 -1
- package/dist/utils/get-property-value.js +42 -3
- package/dist/utils/load-addon-functions-meta.js +31 -0
- package/dist/utils/middleware.d.ts +1 -1
- package/dist/utils/permissions.d.ts +1 -1
- package/dist/utils/post-process.d.ts +27 -7
- package/dist/utils/post-process.js +79 -14
- package/dist/utils/resolve-deploy-target.d.ts +1 -1
- package/dist/utils/resolve-function-meta.d.ts +1 -1
- package/dist/utils/resolve-function-types.d.ts +1 -1
- package/dist/utils/resolve-versions.js +1 -1
- package/dist/utils/schema-generator.d.ts +1 -1
- package/dist/utils/serialize-inspector-state.d.ts +2 -1
- package/dist/utils/serialize-inspector-state.js +2 -0
- package/dist/utils/serialize-openapi-json.d.ts +2 -2
- package/dist/utils/validate-auth-sessionless.js +2 -1
- package/dist/utils/workflow/derive-workflow-plan.d.ts +1 -1
- package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +1 -1
- package/dist/utils/workflow/graph/convert-dsl-to-graph.d.ts +1 -1
- package/dist/utils/workflow/graph/finalize-workflows.js +1 -1
- package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +6 -1
- package/dist/utils/workflow/graph/serialize-workflow-graph.js +26 -2
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +11 -2
- package/package.json +10 -10
- package/run-tests.sh +0 -0
- package/src/add/add-agent.ts +2 -4
- package/src/add/add-auth.ts +2 -2
- package/src/add/add-channel.ts +1 -4
- package/src/add/add-cli.ts +7 -1
- package/src/add/add-credential.ts +3 -6
- package/src/add/add-file-with-factory.ts +2 -6
- package/src/add/add-functions.ts +24 -31
- package/src/add/add-gateway.ts +1 -1
- package/src/add/add-http-route-ref.test.ts +149 -0
- package/src/add/add-http-route.ts +26 -29
- package/src/add/add-keyed-wiring.ts +8 -7
- package/src/add/add-permission.ts +1 -1
- package/src/add/add-personas.test.ts +26 -2
- package/src/add/add-personas.ts +4 -3
- package/src/add/add-scenario-step.test.ts +37 -2
- package/src/add/add-scope.test.ts +15 -15
- package/src/add/add-scope.ts +5 -9
- package/src/add/add-secret.ts +1 -0
- package/src/add/add-system-role.test.ts +4 -4
- package/src/add/add-system-role.ts +2 -4
- package/src/add/add-variable.ts +1 -0
- package/src/add/add-wire-remote-addon.ts +4 -1
- package/src/add/add-workflow-graph-foreach.test.ts +174 -0
- package/src/add/add-workflow-graph-input.test.ts +1 -1
- package/src/add/add-workflow-graph.ts +78 -6
- package/src/add/add-workflow-sleep-expression.test.ts +3 -4
- package/src/add/add-workflow.ts +1 -4
- package/src/add/addon-contracts.test.ts +1 -1
- package/src/add/config-value-metadata.test.ts +94 -0
- package/src/add/secret-sink-check.test.ts +4 -1
- package/src/error-codes.ts +3 -1
- package/src/index.ts +3 -4
- package/src/inspector.ts +19 -2
- package/src/types.ts +25 -28
- package/src/utils/annotate-http-route-auth.test.ts +5 -7
- package/src/utils/annotate-http-route-auth.ts +2 -1
- package/src/utils/check-secret-sinks.ts +4 -1
- package/src/utils/compute-required-schemas.ts +1 -1
- package/src/utils/contract-hashes.test.ts +1 -1
- package/src/utils/contract-hashes.ts +3 -3
- package/src/utils/extract-function-name.ts +1 -1
- package/src/utils/extract-services.ts +1 -2
- package/src/utils/extract-surface-usage.test.ts +147 -0
- package/src/utils/extract-surface-usage.ts +121 -0
- package/src/utils/filter-inspector-state.test.ts +138 -12
- package/src/utils/filter-inspector-state.ts +82 -21
- package/src/utils/filter-utils.ts +1 -1
- package/src/utils/get-property-value.ts +43 -5
- package/src/utils/load-addon-functions-meta.ts +40 -0
- package/src/utils/middleware.ts +1 -1
- package/src/utils/permissions.ts +1 -1
- package/src/utils/post-process.test.ts +59 -2
- package/src/utils/post-process.ts +88 -25
- package/src/utils/resolve-deploy-target.ts +1 -1
- package/src/utils/resolve-function-meta.ts +1 -4
- package/src/utils/resolve-function-types.ts +1 -1
- package/src/utils/resolve-versions.ts +2 -5
- package/src/utils/schema-generator.ts +3 -3
- package/src/utils/serialize-inspector-state.ts +4 -1
- package/src/utils/serialize-mcp-json.ts +1 -1
- package/src/utils/serialize-openapi-json.ts +2 -2
- package/src/utils/validate-auth-sessionless.ts +2 -1
- package/src/utils/validate-tags-resolve-to-middleware.test.ts +4 -1
- package/src/utils/workflow/derive-workflow-plan.test.ts +1 -1
- package/src/utils/workflow/derive-workflow-plan.ts +1 -1
- package/src/utils/workflow/dsl/extract-approval-policy.test.ts +1 -1
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +2 -2
- package/src/utils/workflow/graph/convert-dsl-to-graph-skip.test.ts +1 -1
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +1 -4
- package/src/utils/workflow/graph/finalize-workflow-wires.ts +1 -1
- package/src/utils/workflow/graph/finalize-workflows.ts +2 -2
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +34 -3
- package/src/utils/workflow/graph/workflow-graph.types.ts +12 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/add/add-ai-agent.d.ts +0 -4
- package/dist/add/add-ai-agent.js +0 -442
- package/dist/add/add-ai-scorer.d.ts +0 -2
- package/dist/add/add-ai-scorer.js +0 -61
- package/dist/utils/secret-brokers.d.ts +0 -2
- package/dist/utils/secret-brokers.js +0 -9
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import type { AddWiring, InspectorLogger } from '../types.js';
|
|
3
|
-
export declare function resolveWorkflowReferences(obj: ts.ObjectLiteralExpression, checker: ts.TypeChecker, agentName: string, logger: InspectorLogger): string[] | null;
|
|
4
|
-
export declare const addAIAgent: AddWiring;
|
package/dist/add/add-ai-agent.js
DELETED
|
@@ -1,442 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue, getCommonWireMetaData, } from '../utils/get-property-value.js';
|
|
3
|
-
import { extractWireNames } from '../utils/post-process.js';
|
|
4
|
-
import { extractFunctionName, funcIdToTypeName, } from '../utils/extract-function-name.js';
|
|
5
|
-
import { resolveMiddleware, resolveChannelMiddleware, resolveAIMiddleware, } from '../utils/middleware.js';
|
|
6
|
-
import { resolvePermissions } from '../utils/permissions.js';
|
|
7
|
-
import { ErrorCode } from '../error-codes.js';
|
|
8
|
-
import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js';
|
|
9
|
-
function resolveToolReferences(obj, checker, agentName, logger) {
|
|
10
|
-
const property = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
11
|
-
ts.isIdentifier(p.name) &&
|
|
12
|
-
p.name.text === 'tools');
|
|
13
|
-
if (!property || !ts.isPropertyAssignment(property)) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
const initializer = property.initializer;
|
|
17
|
-
if (!ts.isArrayLiteralExpression(initializer)) {
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
const resolved = [];
|
|
21
|
-
for (const element of initializer.elements) {
|
|
22
|
-
if (ts.isStringLiteral(element)) {
|
|
23
|
-
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' tools array contains a string literal '${element.text}'. ` +
|
|
24
|
-
`Use a function reference instead (e.g., import the pikkuFunc variable).`);
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
if (ts.isCallExpression(element) && ts.isIdentifier(element.expression)) {
|
|
28
|
-
const calleeName = element.expression.text;
|
|
29
|
-
if (calleeName === 'workflow') {
|
|
30
|
-
const [firstArg] = element.arguments;
|
|
31
|
-
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
32
|
-
resolved.push(`workflow:${firstArg.text}`);
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (calleeName === 'ref') {
|
|
37
|
-
const [firstArg] = element.arguments;
|
|
38
|
-
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
39
|
-
resolved.push(firstArg.text);
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
if (ts.isIdentifier(element)) {
|
|
45
|
-
const rpcName = resolveIdentifierToRpcName(element, checker);
|
|
46
|
-
if (rpcName) {
|
|
47
|
-
resolved.push(rpcName);
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' tools array contains identifier '${element.text}' ` +
|
|
51
|
-
`that could not be resolved to a pikkuFunc.`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return resolved.length > 0 ? resolved : null;
|
|
55
|
-
}
|
|
56
|
-
function resolveAgentReferences(obj, checker, agentName, logger) {
|
|
57
|
-
const property = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
58
|
-
ts.isIdentifier(p.name) &&
|
|
59
|
-
p.name.text === 'agents');
|
|
60
|
-
if (!property || !ts.isPropertyAssignment(property)) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
const initializer = property.initializer;
|
|
64
|
-
if (!ts.isArrayLiteralExpression(initializer)) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
const resolved = [];
|
|
68
|
-
for (const element of initializer.elements) {
|
|
69
|
-
if (ts.isStringLiteral(element)) {
|
|
70
|
-
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' agents array contains a string literal '${element.text}'. ` +
|
|
71
|
-
`Use an agent reference instead (e.g., import the pikkuAIAgent variable).`);
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
if (ts.isIdentifier(element)) {
|
|
75
|
-
const name = resolveIdentifierToAgentName(element, checker);
|
|
76
|
-
if (name) {
|
|
77
|
-
resolved.push(name);
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' agents array contains identifier '${element.text}' ` +
|
|
81
|
-
`that could not be resolved to a pikkuAIAgent.`);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return resolved.length > 0 ? resolved : null;
|
|
85
|
-
}
|
|
86
|
-
export function resolveWorkflowReferences(obj, checker, agentName, logger) {
|
|
87
|
-
const property = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
88
|
-
ts.isIdentifier(p.name) &&
|
|
89
|
-
p.name.text === 'workflows');
|
|
90
|
-
if (!property || !ts.isPropertyAssignment(property)) {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
const initializer = property.initializer;
|
|
94
|
-
if (!ts.isArrayLiteralExpression(initializer)) {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
const resolved = [];
|
|
98
|
-
for (const element of initializer.elements) {
|
|
99
|
-
if (ts.isStringLiteral(element)) {
|
|
100
|
-
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' workflows array contains a string literal '${element.text}'. ` +
|
|
101
|
-
`Use a workflow reference instead (e.g., ref('<workflowName>') or import the pikkuWorkflowGraph variable).`);
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
if (ts.isCallExpression(element) && ts.isIdentifier(element.expression)) {
|
|
105
|
-
const calleeName = element.expression.text;
|
|
106
|
-
if (calleeName === 'ref' || calleeName === 'workflow') {
|
|
107
|
-
const [firstArg] = element.arguments;
|
|
108
|
-
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
109
|
-
resolved.push(firstArg.text);
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (ts.isIdentifier(element)) {
|
|
115
|
-
const name = resolveIdentifierToWorkflowName(element, checker);
|
|
116
|
-
if (name) {
|
|
117
|
-
resolved.push(name);
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' workflows array contains identifier '${element.text}' ` +
|
|
121
|
-
`that could not be resolved to a pikkuWorkflowGraph.`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return resolved.length > 0 ? resolved : null;
|
|
125
|
-
}
|
|
126
|
-
function resolveIdentifierToWorkflowName(identifier, checker) {
|
|
127
|
-
const symbol = checker.getSymbolAtLocation(identifier);
|
|
128
|
-
if (!symbol)
|
|
129
|
-
return null;
|
|
130
|
-
let resolved = symbol;
|
|
131
|
-
if (resolved.flags & ts.SymbolFlags.Alias) {
|
|
132
|
-
resolved = checker.getAliasedSymbol(resolved) ?? resolved;
|
|
133
|
-
}
|
|
134
|
-
const decl = resolved.valueDeclaration ?? resolved.declarations?.[0];
|
|
135
|
-
if (!decl)
|
|
136
|
-
return null;
|
|
137
|
-
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
138
|
-
if (ts.isCallExpression(decl.initializer) &&
|
|
139
|
-
ts.isIdentifier(decl.initializer.expression) &&
|
|
140
|
-
(decl.initializer.expression.text === 'pikkuWorkflowGraph' ||
|
|
141
|
-
decl.initializer.expression.text === 'pikkuWorkflow' ||
|
|
142
|
-
decl.initializer.expression.text === 'pikkuWorkflowComplex')) {
|
|
143
|
-
const firstArg = decl.initializer.arguments[0];
|
|
144
|
-
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
145
|
-
for (const prop of firstArg.properties) {
|
|
146
|
-
if (ts.isPropertyAssignment(prop) &&
|
|
147
|
-
ts.isIdentifier(prop.name) &&
|
|
148
|
-
prop.name.text === 'name' &&
|
|
149
|
-
ts.isStringLiteral(prop.initializer)) {
|
|
150
|
-
return prop.initializer.text;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (ts.isIdentifier(decl.name)) {
|
|
155
|
-
return decl.name.text;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
function resolveIdentifierToRpcName(identifier, checker) {
|
|
162
|
-
const symbol = checker.getSymbolAtLocation(identifier);
|
|
163
|
-
if (!symbol)
|
|
164
|
-
return null;
|
|
165
|
-
let resolved = symbol;
|
|
166
|
-
if (resolved.flags & ts.SymbolFlags.Alias) {
|
|
167
|
-
resolved = checker.getAliasedSymbol(resolved) ?? resolved;
|
|
168
|
-
}
|
|
169
|
-
const decl = resolved.valueDeclaration ?? resolved.declarations?.[0];
|
|
170
|
-
if (!decl)
|
|
171
|
-
return null;
|
|
172
|
-
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
173
|
-
if (ts.isCallExpression(decl.initializer) &&
|
|
174
|
-
ts.isIdentifier(decl.initializer.expression)) {
|
|
175
|
-
const callName = decl.initializer.expression.text;
|
|
176
|
-
if (callName === 'pikkuFunc' ||
|
|
177
|
-
callName === 'pikkuSessionlessFunc' ||
|
|
178
|
-
callName === 'pikkuVoidFunc') {
|
|
179
|
-
const firstArg = decl.initializer.arguments[0];
|
|
180
|
-
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
181
|
-
for (const prop of firstArg.properties) {
|
|
182
|
-
if (ts.isPropertyAssignment(prop) &&
|
|
183
|
-
ts.isIdentifier(prop.name) &&
|
|
184
|
-
prop.name.text === 'override' &&
|
|
185
|
-
ts.isStringLiteral(prop.initializer)) {
|
|
186
|
-
return prop.initializer.text;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (ts.isIdentifier(decl.name)) {
|
|
191
|
-
return decl.name.text;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return null;
|
|
197
|
-
}
|
|
198
|
-
function resolveIdentifierToAgentName(identifier, checker) {
|
|
199
|
-
const symbol = checker.getSymbolAtLocation(identifier);
|
|
200
|
-
if (!symbol)
|
|
201
|
-
return null;
|
|
202
|
-
let resolved = symbol;
|
|
203
|
-
if (resolved.flags & ts.SymbolFlags.Alias) {
|
|
204
|
-
resolved = checker.getAliasedSymbol(resolved) ?? resolved;
|
|
205
|
-
}
|
|
206
|
-
const decl = resolved.valueDeclaration ?? resolved.declarations?.[0];
|
|
207
|
-
if (!decl)
|
|
208
|
-
return null;
|
|
209
|
-
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
210
|
-
if (ts.isCallExpression(decl.initializer) &&
|
|
211
|
-
ts.isIdentifier(decl.initializer.expression) &&
|
|
212
|
-
decl.initializer.expression.text === 'pikkuAIAgent') {
|
|
213
|
-
if (ts.isIdentifier(decl.name)) {
|
|
214
|
-
return decl.name.text;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return null;
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* The scorers an agent asks to be graded by, which are plain names rather than
|
|
222
|
-
* references: a scorer is resolved out of the registry at grading time, not
|
|
223
|
-
* imported by the agent, so nothing here has a declaration to chase.
|
|
224
|
-
*/
|
|
225
|
-
function resolveScorerNames(obj, agentName, logger) {
|
|
226
|
-
const property = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
227
|
-
ts.isIdentifier(p.name) &&
|
|
228
|
-
p.name.text === 'scorers');
|
|
229
|
-
if (!property || !ts.isPropertyAssignment(property))
|
|
230
|
-
return null;
|
|
231
|
-
if (!ts.isArrayLiteralExpression(property.initializer))
|
|
232
|
-
return null;
|
|
233
|
-
const names = [];
|
|
234
|
-
for (const element of property.initializer.elements) {
|
|
235
|
-
if (!ts.isStringLiteral(element)) {
|
|
236
|
-
logger.critical(ErrorCode.INVALID_VALUE, `AI agent '${agentName}' lists a scorer that is not an inline string: \`${element.getText()}\`. A scorer is named, not imported, so the name has to be readable from source.`);
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
names.push(element.text);
|
|
240
|
-
}
|
|
241
|
-
return names.length > 0 ? names : null;
|
|
242
|
-
}
|
|
243
|
-
export const addAIAgent = (logger, node, checker, state, options) => {
|
|
244
|
-
if (!ts.isCallExpression(node)) {
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
const args = node.arguments;
|
|
248
|
-
const firstArg = args[0];
|
|
249
|
-
const expression = node.expression;
|
|
250
|
-
if (!ts.isIdentifier(expression) || expression.text !== 'pikkuAIAgent') {
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
if (!firstArg) {
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
const { exportedName } = extractFunctionName(node, checker, state.rootDir);
|
|
257
|
-
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
258
|
-
const obj = firstArg;
|
|
259
|
-
const nameValue = getPropertyValue(obj, 'name');
|
|
260
|
-
const { disabled, tags, summary, description, errors } = getCommonWireMetaData(obj, 'AI agent', nameValue, logger, checker);
|
|
261
|
-
if (disabled)
|
|
262
|
-
return;
|
|
263
|
-
const modelValue = getPropertyValue(obj, 'model');
|
|
264
|
-
const roleValue = getPropertyValue(obj, 'role');
|
|
265
|
-
const personalityValue = getPropertyValue(obj, 'personality');
|
|
266
|
-
const goalValue = getPropertyValue(obj, 'goal');
|
|
267
|
-
const maxStepsValue = getPropertyValue(obj, 'maxSteps');
|
|
268
|
-
const temperatureValue = getPropertyValue(obj, 'temperature');
|
|
269
|
-
const toolChoiceValue = getPropertyValue(obj, 'toolChoice');
|
|
270
|
-
const scorersValue = resolveScorerNames(obj, nameValue || '', logger);
|
|
271
|
-
const toolsValue = resolveToolReferences(obj, checker, nameValue || '', logger);
|
|
272
|
-
if (toolsValue) {
|
|
273
|
-
for (const toolName of toolsValue) {
|
|
274
|
-
if (toolName.startsWith('workflow:') || toolName.includes(':'))
|
|
275
|
-
continue;
|
|
276
|
-
const funcFile = state.functions.files.get(toolName);
|
|
277
|
-
if (funcFile && !state.rpc.internalFiles.has(toolName)) {
|
|
278
|
-
state.rpc.internalFiles.set(toolName, funcFile);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
const agentsValue = resolveAgentReferences(obj, checker, nameValue || '', logger);
|
|
283
|
-
const workflowsValue = resolveWorkflowReferences(obj, checker, nameValue || '', logger);
|
|
284
|
-
if (workflowsValue) {
|
|
285
|
-
for (const workflowName of workflowsValue) {
|
|
286
|
-
state.workflows.invokedWorkflows.add(workflowName);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
if (!nameValue) {
|
|
290
|
-
logger.critical(ErrorCode.MISSING_NAME, "AI agent is missing the required 'name' property.");
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
const agentKey = exportedName || nameValue;
|
|
294
|
-
if (!description) {
|
|
295
|
-
logger.critical(ErrorCode.MISSING_DESCRIPTION, `AI agent '${nameValue}' is missing a description.`);
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
const resolveSchemaRef = (identifier, context) => {
|
|
299
|
-
const symbol = checker.getSymbolAtLocation(identifier);
|
|
300
|
-
if (!symbol)
|
|
301
|
-
return null;
|
|
302
|
-
const decl = symbol.valueDeclaration || symbol.declarations?.[0];
|
|
303
|
-
if (!decl)
|
|
304
|
-
return null;
|
|
305
|
-
let sourceFile;
|
|
306
|
-
if (ts.isImportSpecifier(decl)) {
|
|
307
|
-
const aliasedSymbol = checker.getAliasedSymbol(symbol);
|
|
308
|
-
if (aliasedSymbol) {
|
|
309
|
-
const aliasedDecl = aliasedSymbol.valueDeclaration || aliasedSymbol.declarations?.[0];
|
|
310
|
-
if (aliasedDecl) {
|
|
311
|
-
sourceFile = aliasedDecl.getSourceFile().fileName;
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
return null;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
return null;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
sourceFile = decl.getSourceFile().fileName;
|
|
323
|
-
}
|
|
324
|
-
const vendor = detectSchemaVendorOrError(identifier, checker, logger, context, sourceFile);
|
|
325
|
-
if (!vendor)
|
|
326
|
-
return null;
|
|
327
|
-
return {
|
|
328
|
-
variableName: identifier.text,
|
|
329
|
-
sourceFile,
|
|
330
|
-
vendor,
|
|
331
|
-
};
|
|
332
|
-
};
|
|
333
|
-
let inputSchema = null;
|
|
334
|
-
let outputSchema = null;
|
|
335
|
-
let workingMemorySchema = null;
|
|
336
|
-
const capitalizedName = funcIdToTypeName(agentKey);
|
|
337
|
-
for (const prop of obj.properties) {
|
|
338
|
-
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
|
339
|
-
const propName = prop.name.text;
|
|
340
|
-
if (propName === 'input' || propName === 'output') {
|
|
341
|
-
if (ts.isIdentifier(prop.initializer)) {
|
|
342
|
-
const context = `AI agent '${nameValue}' ${propName}`;
|
|
343
|
-
const ref = resolveSchemaRef(prop.initializer, context);
|
|
344
|
-
if (ref) {
|
|
345
|
-
const schemaName = `${capitalizedName}${propName.charAt(0).toUpperCase() + propName.slice(1)}`;
|
|
346
|
-
state.schemaLookup.set(schemaName, ref);
|
|
347
|
-
state.functions.typesMap.addCustomType(schemaName, 'unknown', []);
|
|
348
|
-
if (propName === 'input') {
|
|
349
|
-
inputSchema = schemaName;
|
|
350
|
-
}
|
|
351
|
-
else {
|
|
352
|
-
outputSchema = schemaName;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
else if (ts.isCallExpression(prop.initializer)) {
|
|
357
|
-
const schemaName = `${capitalizedName}${propName.charAt(0).toUpperCase() + propName.slice(1)}`;
|
|
358
|
-
logger.critical(ErrorCode.INLINE_SCHEMA, `Inline schemas are not supported for '${propName}' in AI agent '${nameValue}'.\n` +
|
|
359
|
-
` Extract to an exported variable:\n` +
|
|
360
|
-
` export const ${schemaName} = ${prop.initializer.getText()}\n` +
|
|
361
|
-
` Then use: ${propName}: ${schemaName}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
else if (propName === 'memory' &&
|
|
365
|
-
ts.isObjectLiteralExpression(prop.initializer)) {
|
|
366
|
-
for (const memProp of prop.initializer.properties) {
|
|
367
|
-
if (ts.isPropertyAssignment(memProp) &&
|
|
368
|
-
ts.isIdentifier(memProp.name) &&
|
|
369
|
-
memProp.name.text === 'workingMemory' &&
|
|
370
|
-
ts.isIdentifier(memProp.initializer)) {
|
|
371
|
-
const context = `AI agent '${nameValue}' workingMemory`;
|
|
372
|
-
const ref = resolveSchemaRef(memProp.initializer, context);
|
|
373
|
-
if (ref) {
|
|
374
|
-
const schemaName = `${capitalizedName}WorkingMemory`;
|
|
375
|
-
state.schemaLookup.set(schemaName, ref);
|
|
376
|
-
state.functions.typesMap.addCustomType(schemaName, 'unknown', []);
|
|
377
|
-
workingMemorySchema = schemaName;
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
385
|
-
const channelMiddleware = resolveChannelMiddleware(state, obj, tags, checker);
|
|
386
|
-
const aiMiddleware = resolveAIMiddleware(state, obj, checker);
|
|
387
|
-
const permissions = resolvePermissions(state, obj, tags, checker);
|
|
388
|
-
state.serviceAggregation.usedFunctions.add(agentKey);
|
|
389
|
-
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
390
|
-
extractWireNames(permissions).forEach((name) => state.serviceAggregation.usedPermissions.add(name));
|
|
391
|
-
if (exportedName) {
|
|
392
|
-
state.agents.files.set(agentKey, {
|
|
393
|
-
path: node.getSourceFile().fileName,
|
|
394
|
-
exportedName,
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
state.agents.agentsMeta[agentKey] = {
|
|
398
|
-
name: nameValue,
|
|
399
|
-
description,
|
|
400
|
-
role: roleValue || undefined,
|
|
401
|
-
personality: personalityValue || undefined,
|
|
402
|
-
goal: goalValue || '',
|
|
403
|
-
model: modelValue || '',
|
|
404
|
-
summary,
|
|
405
|
-
errors,
|
|
406
|
-
sourceFile: node.getSourceFile().fileName,
|
|
407
|
-
exportedName: exportedName || undefined,
|
|
408
|
-
...(maxStepsValue !== null && { maxSteps: maxStepsValue }),
|
|
409
|
-
...(temperatureValue !== null && { temperature: temperatureValue }),
|
|
410
|
-
...(toolChoiceValue !== null && {
|
|
411
|
-
toolChoice: toolChoiceValue,
|
|
412
|
-
}),
|
|
413
|
-
...(toolsValue !== null && { tools: toolsValue }),
|
|
414
|
-
...(agentsValue !== null && { agents: agentsValue }),
|
|
415
|
-
...(workflowsValue !== null && { workflows: workflowsValue }),
|
|
416
|
-
...(scorersValue !== null && { scorers: scorersValue }),
|
|
417
|
-
tags,
|
|
418
|
-
inputSchema,
|
|
419
|
-
outputSchema,
|
|
420
|
-
workingMemorySchema,
|
|
421
|
-
middleware,
|
|
422
|
-
channelMiddleware,
|
|
423
|
-
aiMiddleware,
|
|
424
|
-
permissions,
|
|
425
|
-
};
|
|
426
|
-
// AI agent functions require platform services that aren't visible
|
|
427
|
-
// through parameter destructuring
|
|
428
|
-
const funcMeta = state.functions.meta[agentKey];
|
|
429
|
-
if (funcMeta?.services) {
|
|
430
|
-
for (const svc of [
|
|
431
|
-
'aiStorage',
|
|
432
|
-
'aiRunState',
|
|
433
|
-
'agentRunService',
|
|
434
|
-
'aiAgentRunner',
|
|
435
|
-
]) {
|
|
436
|
-
if (!funcMeta.services.services.includes(svc)) {
|
|
437
|
-
funcMeta.services.services.push(svc);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
3
|
-
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
4
|
-
import { ErrorCode } from '../error-codes.js';
|
|
5
|
-
/**
|
|
6
|
-
* `pikkuAIScorer` grades in code and `pikkuAIJudge` grades with a model, which
|
|
7
|
-
* is the whole difference between the two lanes — so the lane is read off which
|
|
8
|
-
* constructor was called rather than from a field an author could contradict.
|
|
9
|
-
*/
|
|
10
|
-
const LANES = {
|
|
11
|
-
pikkuAIScorer: 'fast',
|
|
12
|
-
pikkuAIJudge: 'slow',
|
|
13
|
-
};
|
|
14
|
-
export const addAIScorer = (logger, node, checker, state) => {
|
|
15
|
-
if (!ts.isCallExpression(node))
|
|
16
|
-
return;
|
|
17
|
-
const expression = node.expression;
|
|
18
|
-
if (!ts.isIdentifier(expression))
|
|
19
|
-
return;
|
|
20
|
-
const lane = LANES[expression.text];
|
|
21
|
-
if (!lane)
|
|
22
|
-
return;
|
|
23
|
-
const firstArg = node.arguments[0];
|
|
24
|
-
if (!firstArg || !ts.isObjectLiteralExpression(firstArg))
|
|
25
|
-
return;
|
|
26
|
-
const obj = firstArg;
|
|
27
|
-
const { exportedName } = extractFunctionName(node, checker, state.rootDir);
|
|
28
|
-
const nameValue = getPropertyValue(obj, 'name');
|
|
29
|
-
if (!nameValue) {
|
|
30
|
-
logger.critical(ErrorCode.MISSING_NAME, "AI scorer is missing the required 'name' property.");
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const description = getPropertyValue(obj, 'description');
|
|
34
|
-
if (!description) {
|
|
35
|
-
logger.critical(ErrorCode.MISSING_DESCRIPTION, `AI scorer '${nameValue}' is missing the required 'description' property.`);
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
const sampleRateValue = getPropertyValue(obj, 'sampleRate');
|
|
39
|
-
if (sampleRateValue !== null &&
|
|
40
|
-
(sampleRateValue < 0 || sampleRateValue > 1)) {
|
|
41
|
-
logger.critical(ErrorCode.INVALID_VALUE, `AI scorer '${nameValue}' has a sampleRate of ${sampleRateValue} — it is the fraction of live runs to grade, so it must be between 0 and 1.`);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const requiresReference = getPropertyValue(obj, 'requiresReference') ?? false;
|
|
45
|
-
const scorerKey = exportedName || nameValue;
|
|
46
|
-
if (exportedName) {
|
|
47
|
-
state.scorers.files.set(scorerKey, {
|
|
48
|
-
path: node.getSourceFile().fileName,
|
|
49
|
-
exportedName,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
state.scorers.scorersMeta[scorerKey] = {
|
|
53
|
-
name: nameValue,
|
|
54
|
-
description,
|
|
55
|
-
lane,
|
|
56
|
-
sampleRate: sampleRateValue ?? 1,
|
|
57
|
-
requiresReference,
|
|
58
|
-
sourceFile: node.getSourceFile().fileName,
|
|
59
|
-
exportedName: exportedName || undefined,
|
|
60
|
-
};
|
|
61
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/** The console's secret administration functions, and nothing else. */
|
|
2
|
-
const SECRET_BROKER_FUNCTIONS = new Set([
|
|
3
|
-
'pikkuConsoleSetSecret',
|
|
4
|
-
'pikkuConsoleGetSecret',
|
|
5
|
-
'pikkuConsoleHasSecret',
|
|
6
|
-
]);
|
|
7
|
-
/** Whether this function keeps the full `SecretService`. */
|
|
8
|
-
export const isSecretBrokerFunction = (functionId) => SECRET_BROKER_FUNCTIONS.has(functionId) ||
|
|
9
|
-
SECRET_BROKER_FUNCTIONS.has(functionId.split(':').pop() ?? '');
|