wave-agent-sdk 0.16.0 → 0.16.1
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/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +9 -5
- package/dist/services/authService.d.ts +8 -2
- package/dist/services/authService.d.ts.map +1 -1
- package/dist/services/authService.js +55 -22
- package/dist/telemetry/events.d.ts.map +1 -1
- package/dist/telemetry/events.js +6 -2
- package/dist/telemetry/instrumentation.d.ts +5 -0
- package/dist/telemetry/instrumentation.d.ts.map +1 -1
- package/dist/telemetry/instrumentation.js +21 -0
- package/dist/tools/toolSearchTool.js +1 -1
- package/dist/types/auth.d.ts +5 -0
- package/dist/types/auth.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/prompts/index.ts +9 -5
- package/src/services/authService.ts +72 -31
- package/src/telemetry/events.ts +10 -2
- package/src/telemetry/instrumentation.ts +21 -0
- package/src/tools/toolSearchTool.ts +1 -1
- package/src/types/auth.ts +6 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAmBzD,eAAO,MAAM,kBAAkB,oKAAoK,CAAC;AAEpM,eAAO,MAAM,kBAAkB,opIAcqQ,CAAC;AAErS,eAAO,MAAM,wBAAwB,25DASqmB,CAAC;AAE3oB,eAAO,MAAM,WAAW,ihDAWqH,CAAC;AAE9I;;GAEG;AACH,eAAO,MAAM,wBAAwB,+uBAWiH,CAAC;AAEvJ,eAAO,MAAM,qBAAqB,6sBAMuL,CAAC;AAE1N,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,OAAO,EACnB,UAAU,GAAE,OAAe,GAC1B,MAAM,CAmFR;AAED,eAAO,MAAM,qBAAqB,oKAAqB,CAAC;AAExD,eAAO,MAAM,8BAA8B,44DA8CI,CAAC;AAEhD,eAAO,MAAM,yBAAyB,wHAAwH,CAAC;AAC/J,eAAO,MAAM,iBAAiB,qWAG4B,CAAC;AAE3D,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE;QACT,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,UAAU,CAAC,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,cAAc,CAAC,EAAE,cAAc,CAAC;CAC5B,GACL,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI/C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAmBzD,eAAO,MAAM,kBAAkB,oKAAoK,CAAC;AAEpM,eAAO,MAAM,kBAAkB,opIAcqQ,CAAC;AAErS,eAAO,MAAM,wBAAwB,25DASqmB,CAAC;AAE3oB,eAAO,MAAM,WAAW,ihDAWqH,CAAC;AAE9I;;GAEG;AACH,eAAO,MAAM,wBAAwB,+uBAWiH,CAAC;AAEvJ,eAAO,MAAM,qBAAqB,6sBAMuL,CAAC;AAE1N,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,OAAO,EACnB,UAAU,GAAE,OAAe,GAC1B,MAAM,CAmFR;AAED,eAAO,MAAM,qBAAqB,oKAAqB,CAAC;AAExD,eAAO,MAAM,8BAA8B,44DA8CI,CAAC;AAEhD,eAAO,MAAM,yBAAyB,wHAAwH,CAAC;AAC/J,eAAO,MAAM,iBAAiB,qWAG4B,CAAC;AAE3D,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE;QACT,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,UAAU,CAAC,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,cAAc,CAAC,EAAE,cAAc,CAAC;CAC5B,GACL,MAAM,CA2ER;AAED,wBAAgB,iCAAiC,CAC/C,oBAAoB,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,GACd,MAAM,CAkCR"}
|
package/dist/prompts/index.js
CHANGED
|
@@ -207,11 +207,15 @@ export function buildSystemPrompt(basePrompt, tools, options = {}) {
|
|
|
207
207
|
if (tools.length > 0) {
|
|
208
208
|
prompt += `\n\n${TOOL_POLICY}`;
|
|
209
209
|
}
|
|
210
|
-
// List available deferred tool names so the model knows they exist
|
|
211
|
-
//
|
|
212
|
-
const
|
|
213
|
-
if (
|
|
214
|
-
|
|
210
|
+
// List available deferred tool names with descriptions so the model knows they exist
|
|
211
|
+
// and can decide which ones to discover via ToolSearch
|
|
212
|
+
const deferredTools = tools.filter(isDeferredTool);
|
|
213
|
+
if (deferredTools.length > 0) {
|
|
214
|
+
const lines = deferredTools.map((t) => {
|
|
215
|
+
const desc = t.config.function?.description;
|
|
216
|
+
return desc ? `${t.name} - ${desc}` : t.name;
|
|
217
|
+
});
|
|
218
|
+
prompt += `\n\n<available-deferred-tools>\n${lines.join("\n")}\nThese tools are NOT loaded yet — call ${TOOL_SEARCH_TOOL_NAME} first to discover their schemas before invoking them.</available-deferred-tools>`;
|
|
215
219
|
}
|
|
216
220
|
prompt += `\n\n${OUTPUT_EFFICIENCY_PROMPT}`;
|
|
217
221
|
prompt += `\n\n${TONE_AND_STYLE_PROMPT}`;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Handles SSO authentication via the admin server.
|
|
5
5
|
* Manages auth token storage in ~/.wave/auth.json.
|
|
6
6
|
*/
|
|
7
|
-
import type { AuthConfig } from "../types/auth.js";
|
|
7
|
+
import type { AuthConfig, AuthUser } from "../types/auth.js";
|
|
8
8
|
export declare class AuthService {
|
|
9
9
|
private static instance;
|
|
10
10
|
static getInstance(): AuthService;
|
|
@@ -17,12 +17,18 @@ export declare class AuthService {
|
|
|
17
17
|
login(options?: {
|
|
18
18
|
/** Callback to receive the auth URL (for display in CLI). */
|
|
19
19
|
onAuthUrl?: (url: string) => void;
|
|
20
|
-
/** Read
|
|
20
|
+
/** Read authorization code manually (e.g. from stdin). Resolves with code or rejects on cancel. */
|
|
21
21
|
readToken?: () => Promise<string>;
|
|
22
22
|
}): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Exchange a short-lived authorization code for a JWT token.
|
|
25
|
+
* Returns both the token and user info.
|
|
26
|
+
*/
|
|
27
|
+
private exchangeCode;
|
|
23
28
|
private startLocalAuthServer;
|
|
24
29
|
private openBrowser;
|
|
25
30
|
isSSOAuthenticated(): boolean;
|
|
31
|
+
getAuthUser(): AuthUser | undefined;
|
|
26
32
|
}
|
|
27
33
|
export declare const authService: AuthService;
|
|
28
34
|
//# sourceMappingURL=authService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authService.d.ts","sourceRoot":"","sources":["../../src/services/authService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"authService.d.ts","sourceRoot":"","sources":["../../src/services/authService.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI7D,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IAErC,MAAM,CAAC,WAAW,IAAI,WAAW;IAOjC,WAAW,IAAI,MAAM;IAKrB,QAAQ,IAAI,UAAU;IAatB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAUlC,SAAS,IAAI,IAAI;IAajB,WAAW,IAAI,MAAM,GAAG,SAAS;IAKjC,eAAe,IAAI,MAAM;IAUnB,KAAK,CAAC,OAAO,CAAC,EAAE;QACpB,6DAA6D;QAC7D,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAClC,mGAAmG;QACnG,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;KACnC,GAAG,OAAO,CAAC,MAAM,CAAC;IAmBnB;;;OAGG;YACW,YAAY;IA0B1B,OAAO,CAAC,oBAAoB;YAoGd,WAAW;IAmBzB,kBAAkB,IAAI,OAAO;IAI7B,WAAW,IAAI,QAAQ,GAAG,SAAS;CAIpC;AAED,eAAO,MAAM,WAAW,aAA4B,CAAC"}
|
|
@@ -71,39 +71,68 @@ export class AuthService {
|
|
|
71
71
|
}
|
|
72
72
|
async login(options) {
|
|
73
73
|
const adminUrl = this.getAdminBaseUrl();
|
|
74
|
-
//
|
|
75
|
-
const
|
|
76
|
-
if (!providersResponse.ok) {
|
|
77
|
-
throw new Error(`Failed to fetch SSO providers: ${providersResponse.status} ${providersResponse.statusText}`);
|
|
78
|
-
}
|
|
79
|
-
const providers = (await providersResponse.json());
|
|
80
|
-
if (!providers || providers.length === 0) {
|
|
81
|
-
throw new Error("No SSO providers available");
|
|
82
|
-
}
|
|
83
|
-
const provider = providers[0].provider;
|
|
84
|
-
// Step 2-5: Start local server, open browser, wait for callback or manual input
|
|
85
|
-
const token = await this.startLocalAuthServer(adminUrl, provider, {
|
|
74
|
+
// Start local server, open browser, wait for callback or manual input
|
|
75
|
+
const { code } = await this.startLocalAuthServer(adminUrl, {
|
|
86
76
|
onAuthUrl: options?.onAuthUrl,
|
|
87
77
|
readToken: options?.readToken,
|
|
88
78
|
});
|
|
89
|
-
//
|
|
79
|
+
// Exchange authorization code for JWT (includes user info)
|
|
80
|
+
const { token, user } = await this.exchangeCode(adminUrl, code);
|
|
81
|
+
// Save the token and user info (preserve existing keys)
|
|
90
82
|
const existing = this.loadAuth();
|
|
91
|
-
this.saveAuth({ ...existing, SSO_TOKEN: token });
|
|
83
|
+
this.saveAuth({ ...existing, SSO_TOKEN: token, user });
|
|
92
84
|
return token;
|
|
93
85
|
}
|
|
94
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Exchange a short-lived authorization code for a JWT token.
|
|
88
|
+
* Returns both the token and user info.
|
|
89
|
+
*/
|
|
90
|
+
async exchangeCode(adminUrl, code) {
|
|
91
|
+
const exchangeUrl = `${adminUrl}/api/auth/exchange`;
|
|
92
|
+
const response = await fetch(exchangeUrl, {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: { "Content-Type": "application/json" },
|
|
95
|
+
body: JSON.stringify({ code }),
|
|
96
|
+
});
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
const text = await response.text();
|
|
99
|
+
throw new Error(`Token exchange failed (${response.status}): ${text}`);
|
|
100
|
+
}
|
|
101
|
+
const data = (await response.json());
|
|
102
|
+
return {
|
|
103
|
+
token: data.token,
|
|
104
|
+
user: { id: data.user.id, email: data.user.email },
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
startLocalAuthServer(adminUrl, options) {
|
|
95
108
|
return new Promise((resolve, reject) => {
|
|
96
109
|
let settled = false;
|
|
97
110
|
const server = createServer((req, res) => {
|
|
98
111
|
if (req.url) {
|
|
99
112
|
const parsedUrl = new URL(req.url, `http://127.0.0.1`);
|
|
100
|
-
const
|
|
113
|
+
const code = parsedUrl.searchParams.get("code");
|
|
114
|
+
const error = parsedUrl.searchParams.get("error");
|
|
115
|
+
if (error) {
|
|
116
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
117
|
+
res.end(`<html><body><h1>Authentication failed</h1><p>${parsedUrl.searchParams.get("error_description") || error}</p></body></html>`);
|
|
118
|
+
if (!settled) {
|
|
119
|
+
settled = true;
|
|
120
|
+
server.close();
|
|
121
|
+
reject(new Error(`SSO login failed: ${error}`));
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (!code) {
|
|
126
|
+
res.writeHead(404, { "Content-Type": "text/html" });
|
|
127
|
+
res.end("<html><body><h1>Not Found</h1></body></html>");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
101
130
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
102
131
|
res.end("<html><body><h1>Authentication successful, you can close this window</h1></body></html>");
|
|
103
|
-
if (
|
|
132
|
+
if (!settled) {
|
|
104
133
|
settled = true;
|
|
105
134
|
server.close();
|
|
106
|
-
resolve(
|
|
135
|
+
resolve({ code, user: { id: "", email: undefined } });
|
|
107
136
|
}
|
|
108
137
|
}
|
|
109
138
|
});
|
|
@@ -117,7 +146,7 @@ export class AuthService {
|
|
|
117
146
|
}
|
|
118
147
|
const port = address.port;
|
|
119
148
|
const callbackUrl = `http://127.0.0.1:${port}`;
|
|
120
|
-
const authUrl = `${adminUrl}/
|
|
149
|
+
const authUrl = `${adminUrl}/login?callback_url=${encodeURIComponent(callbackUrl)}`;
|
|
121
150
|
// Notify caller of the auth URL
|
|
122
151
|
options?.onAuthUrl?.(authUrl);
|
|
123
152
|
// Try to open browser; if it fails, keep server alive for manual visit
|
|
@@ -128,13 +157,13 @@ export class AuthService {
|
|
|
128
157
|
// Browser not available — server stays alive
|
|
129
158
|
}
|
|
130
159
|
});
|
|
131
|
-
// If manual
|
|
160
|
+
// If manual code reading is provided, race between server callback and user input
|
|
132
161
|
if (options?.readToken) {
|
|
133
|
-
options.readToken().then((
|
|
162
|
+
options.readToken().then((code) => {
|
|
134
163
|
if (!settled) {
|
|
135
164
|
settled = true;
|
|
136
165
|
server.close();
|
|
137
|
-
resolve(
|
|
166
|
+
resolve({ code, user: { id: "", email: undefined } });
|
|
138
167
|
}
|
|
139
168
|
}, () => {
|
|
140
169
|
// Manual input cancelled or closed, server keeps waiting for callback
|
|
@@ -171,5 +200,9 @@ export class AuthService {
|
|
|
171
200
|
isSSOAuthenticated() {
|
|
172
201
|
return this.getSSOToken() !== undefined;
|
|
173
202
|
}
|
|
203
|
+
getAuthUser() {
|
|
204
|
+
const config = this.loadAuth();
|
|
205
|
+
return config.user;
|
|
206
|
+
}
|
|
174
207
|
}
|
|
175
208
|
export const authService = AuthService.getInstance();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/telemetry/events.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/telemetry/events.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AA2B3D;;GAEG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC3C,OAAO,CAAC,IAAI,CAAC,CAwBf"}
|
package/dist/telemetry/events.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Provides the `logOTelEvent` API for structured session lifecycle events
|
|
5
5
|
* with PII gates.
|
|
6
6
|
*/
|
|
7
|
-
import { isInitialized, getCurrentConfig } from "./instrumentation.js";
|
|
7
|
+
import { isInitialized, getCurrentConfig, getTelemetryAttributes, } from "./instrumentation.js";
|
|
8
8
|
let cachedLogger;
|
|
9
9
|
async function getOTelLogger() {
|
|
10
10
|
if (cachedLogger)
|
|
@@ -39,6 +39,10 @@ export async function logOTelEvent(eventName, metadata) {
|
|
|
39
39
|
}
|
|
40
40
|
log.emit({
|
|
41
41
|
body: eventName,
|
|
42
|
-
attributes: {
|
|
42
|
+
attributes: {
|
|
43
|
+
"event.name": eventName,
|
|
44
|
+
...getTelemetryAttributes(),
|
|
45
|
+
...attributes,
|
|
46
|
+
},
|
|
43
47
|
});
|
|
44
48
|
}
|
|
@@ -62,4 +62,9 @@ export declare function getCurrentConfig(): TelemetryConfig | undefined;
|
|
|
62
62
|
*/
|
|
63
63
|
export declare function isInitialized(): boolean;
|
|
64
64
|
export { JsonlSpanExporter, JsonlLogExporter };
|
|
65
|
+
/**
|
|
66
|
+
* Get telemetry attributes based on the authenticated SSO user.
|
|
67
|
+
* Returns user.id and user.email when SSO authenticated, empty object otherwise.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getTelemetryAttributes(): Record<string, string>;
|
|
65
70
|
//# sourceMappingURL=instrumentation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/telemetry/instrumentation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/telemetry/instrumentation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,eAAe,EAGhB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;AA2JjC;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GACxC,eAAe,CAmBjB;AAwCD;;GAEG;AACH,cAAM,iBAAkB,YAAW,YAAY;IAC7C,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,CAAC,EAAE,MAAM;IAI7B,MAAM,CACJ,KAAK,EAAE,YAAY,EAAE,EACrB,cAAc,EAAE,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACjD,IAAI;IAwBP,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B;AAED;;GAEG;AACH,cAAM,gBAAiB,YAAW,iBAAiB;IACjD,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,CAAC,EAAE,MAAM;IAI7B,MAAM,CACJ,IAAI,EAAE,iBAAiB,EAAE,EACzB,cAAc,EAAE,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GACjD,IAAI;IAuBP,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAChC,OAAO,CAAC,IAAI,CAAC,CA8Ef;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAuBvD;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,cAAc,oBAAoB,CAAC,GAAG,SAAS,CAE5E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,eAAe,GAAG,SAAS,CAE9D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAGD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAc/D"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { logger } from "../utils/globalLogger.js";
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
|
+
import { AuthService } from "../services/authService.js";
|
|
9
10
|
// Lazy-loaded OTEL modules — only imported when telemetry is initialized
|
|
10
11
|
let sdkNode;
|
|
11
12
|
let api;
|
|
@@ -369,3 +370,23 @@ export function isInitialized() {
|
|
|
369
370
|
}
|
|
370
371
|
// Export JSONL exporters for testing
|
|
371
372
|
export { JsonlSpanExporter, JsonlLogExporter };
|
|
373
|
+
/**
|
|
374
|
+
* Get telemetry attributes based on the authenticated SSO user.
|
|
375
|
+
* Returns user.id and user.email when SSO authenticated, empty object otherwise.
|
|
376
|
+
*/
|
|
377
|
+
export function getTelemetryAttributes() {
|
|
378
|
+
try {
|
|
379
|
+
const user = AuthService.getInstance().getAuthUser();
|
|
380
|
+
if (user) {
|
|
381
|
+
const attrs = { "user.id": user.id };
|
|
382
|
+
if (user.email) {
|
|
383
|
+
attrs["user.email"] = user.email;
|
|
384
|
+
}
|
|
385
|
+
return attrs;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
catch {
|
|
389
|
+
// AuthService not available or not authenticated
|
|
390
|
+
}
|
|
391
|
+
return {};
|
|
392
|
+
}
|
|
@@ -103,7 +103,7 @@ export const toolSearchTool = {
|
|
|
103
103
|
name: TOOL_SEARCH_TOOL_NAME,
|
|
104
104
|
description: `Fetches full schema definitions for deferred tools so they can be called.
|
|
105
105
|
|
|
106
|
-
Deferred tools appear by name in <available-deferred-tools> messages.
|
|
106
|
+
Deferred tools appear by name and description in <available-deferred-tools> messages. The full parameter schema is NOT loaded yet — use this tool to fetch it before invoking a deferred tool. This tool takes a query, matches it against the deferred tool list, and returns the matched tools' complete JSONSchema definitions inside a <functions> block. Once a tool's schema appears in that result, it is callable exactly like any tool defined at the top of the prompt.
|
|
107
107
|
|
|
108
108
|
Result format: each matched tool appears as one <function>{"description": "...", "name": "...", "parameters": {...}}`,
|
|
109
109
|
parameters: {
|
package/dist/types/auth.d.ts
CHANGED
package/dist/types/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/types/auth.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/types/auth.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB"}
|
package/package.json
CHANGED
package/src/prompts/index.ts
CHANGED
|
@@ -260,11 +260,15 @@ export function buildSystemPrompt(
|
|
|
260
260
|
prompt += `\n\n${TOOL_POLICY}`;
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
-
// List available deferred tool names so the model knows they exist
|
|
264
|
-
//
|
|
265
|
-
const
|
|
266
|
-
if (
|
|
267
|
-
|
|
263
|
+
// List available deferred tool names with descriptions so the model knows they exist
|
|
264
|
+
// and can decide which ones to discover via ToolSearch
|
|
265
|
+
const deferredTools = tools.filter(isDeferredTool);
|
|
266
|
+
if (deferredTools.length > 0) {
|
|
267
|
+
const lines = deferredTools.map((t) => {
|
|
268
|
+
const desc = t.config.function?.description;
|
|
269
|
+
return desc ? `${t.name} - ${desc}` : t.name;
|
|
270
|
+
});
|
|
271
|
+
prompt += `\n\n<available-deferred-tools>\n${lines.join("\n")}\nThese tools are NOT loaded yet — call ${TOOL_SEARCH_TOOL_NAME} first to discover their schemas before invoking them.</available-deferred-tools>`;
|
|
268
272
|
}
|
|
269
273
|
|
|
270
274
|
prompt += `\n\n${OUTPUT_EFFICIENCY_PROMPT}`;
|
|
@@ -19,7 +19,7 @@ import { createServer, Server } from "http";
|
|
|
19
19
|
import { URL } from "url";
|
|
20
20
|
import { execFile } from "child_process";
|
|
21
21
|
import { promisify } from "util";
|
|
22
|
-
import type { AuthConfig } from "../types/auth.js";
|
|
22
|
+
import type { AuthConfig, AuthUser } from "../types/auth.js";
|
|
23
23
|
|
|
24
24
|
const execFileAsync = promisify(execFile);
|
|
25
25
|
|
|
@@ -92,64 +92,100 @@ export class AuthService {
|
|
|
92
92
|
async login(options?: {
|
|
93
93
|
/** Callback to receive the auth URL (for display in CLI). */
|
|
94
94
|
onAuthUrl?: (url: string) => void;
|
|
95
|
-
/** Read
|
|
95
|
+
/** Read authorization code manually (e.g. from stdin). Resolves with code or rejects on cancel. */
|
|
96
96
|
readToken?: () => Promise<string>;
|
|
97
97
|
}): Promise<string> {
|
|
98
98
|
const adminUrl = this.getAdminBaseUrl();
|
|
99
99
|
|
|
100
|
-
//
|
|
101
|
-
const
|
|
102
|
-
if (!providersResponse.ok) {
|
|
103
|
-
throw new Error(
|
|
104
|
-
`Failed to fetch SSO providers: ${providersResponse.status} ${providersResponse.statusText}`,
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
const providers = (await providersResponse.json()) as {
|
|
108
|
-
provider: string;
|
|
109
|
-
displayName: string;
|
|
110
|
-
}[];
|
|
111
|
-
if (!providers || providers.length === 0) {
|
|
112
|
-
throw new Error("No SSO providers available");
|
|
113
|
-
}
|
|
114
|
-
const provider = providers[0].provider;
|
|
115
|
-
|
|
116
|
-
// Step 2-5: Start local server, open browser, wait for callback or manual input
|
|
117
|
-
const token = await this.startLocalAuthServer(adminUrl, provider, {
|
|
100
|
+
// Start local server, open browser, wait for callback or manual input
|
|
101
|
+
const { code } = await this.startLocalAuthServer(adminUrl, {
|
|
118
102
|
onAuthUrl: options?.onAuthUrl,
|
|
119
103
|
readToken: options?.readToken,
|
|
120
104
|
});
|
|
121
105
|
|
|
122
|
-
//
|
|
106
|
+
// Exchange authorization code for JWT (includes user info)
|
|
107
|
+
const { token, user } = await this.exchangeCode(adminUrl, code);
|
|
108
|
+
|
|
109
|
+
// Save the token and user info (preserve existing keys)
|
|
123
110
|
const existing = this.loadAuth();
|
|
124
|
-
this.saveAuth({ ...existing, SSO_TOKEN: token });
|
|
111
|
+
this.saveAuth({ ...existing, SSO_TOKEN: token, user });
|
|
125
112
|
|
|
126
113
|
return token;
|
|
127
114
|
}
|
|
128
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Exchange a short-lived authorization code for a JWT token.
|
|
118
|
+
* Returns both the token and user info.
|
|
119
|
+
*/
|
|
120
|
+
private async exchangeCode(
|
|
121
|
+
adminUrl: string,
|
|
122
|
+
code: string,
|
|
123
|
+
): Promise<{ token: string; user: AuthUser }> {
|
|
124
|
+
const exchangeUrl = `${adminUrl}/api/auth/exchange`;
|
|
125
|
+
const response = await fetch(exchangeUrl, {
|
|
126
|
+
method: "POST",
|
|
127
|
+
headers: { "Content-Type": "application/json" },
|
|
128
|
+
body: JSON.stringify({ code }),
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (!response.ok) {
|
|
132
|
+
const text = await response.text();
|
|
133
|
+
throw new Error(`Token exchange failed (${response.status}): ${text}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const data = (await response.json()) as {
|
|
137
|
+
token: string;
|
|
138
|
+
user: { id: string; email?: string };
|
|
139
|
+
};
|
|
140
|
+
return {
|
|
141
|
+
token: data.token,
|
|
142
|
+
user: { id: data.user.id, email: data.user.email },
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
129
146
|
private startLocalAuthServer(
|
|
130
147
|
adminUrl: string,
|
|
131
|
-
provider: string,
|
|
132
148
|
options?: {
|
|
133
149
|
onAuthUrl?: (url: string) => void;
|
|
134
150
|
readToken?: () => Promise<string>;
|
|
135
151
|
},
|
|
136
|
-
): Promise<string> {
|
|
152
|
+
): Promise<{ code: string; user: AuthUser }> {
|
|
137
153
|
return new Promise((resolve, reject) => {
|
|
138
154
|
let settled = false;
|
|
139
155
|
const server: Server = createServer((req, res) => {
|
|
140
156
|
if (req.url) {
|
|
141
157
|
const parsedUrl = new URL(req.url, `http://127.0.0.1`);
|
|
142
|
-
const
|
|
158
|
+
const code = parsedUrl.searchParams.get("code");
|
|
159
|
+
const error = parsedUrl.searchParams.get("error");
|
|
160
|
+
|
|
161
|
+
if (error) {
|
|
162
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
163
|
+
res.end(
|
|
164
|
+
`<html><body><h1>Authentication failed</h1><p>${parsedUrl.searchParams.get("error_description") || error}</p></body></html>`,
|
|
165
|
+
);
|
|
166
|
+
if (!settled) {
|
|
167
|
+
settled = true;
|
|
168
|
+
server.close();
|
|
169
|
+
reject(new Error(`SSO login failed: ${error}`));
|
|
170
|
+
}
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!code) {
|
|
175
|
+
res.writeHead(404, { "Content-Type": "text/html" });
|
|
176
|
+
res.end("<html><body><h1>Not Found</h1></body></html>");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
143
179
|
|
|
144
180
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
145
181
|
res.end(
|
|
146
182
|
"<html><body><h1>Authentication successful, you can close this window</h1></body></html>",
|
|
147
183
|
);
|
|
148
184
|
|
|
149
|
-
if (
|
|
185
|
+
if (!settled) {
|
|
150
186
|
settled = true;
|
|
151
187
|
server.close();
|
|
152
|
-
resolve(
|
|
188
|
+
resolve({ code, user: { id: "", email: undefined } });
|
|
153
189
|
}
|
|
154
190
|
}
|
|
155
191
|
});
|
|
@@ -164,7 +200,7 @@ export class AuthService {
|
|
|
164
200
|
}
|
|
165
201
|
const port = address.port;
|
|
166
202
|
const callbackUrl = `http://127.0.0.1:${port}`;
|
|
167
|
-
const authUrl = `${adminUrl}/
|
|
203
|
+
const authUrl = `${adminUrl}/login?callback_url=${encodeURIComponent(callbackUrl)}`;
|
|
168
204
|
|
|
169
205
|
// Notify caller of the auth URL
|
|
170
206
|
options?.onAuthUrl?.(authUrl);
|
|
@@ -177,14 +213,14 @@ export class AuthService {
|
|
|
177
213
|
}
|
|
178
214
|
});
|
|
179
215
|
|
|
180
|
-
// If manual
|
|
216
|
+
// If manual code reading is provided, race between server callback and user input
|
|
181
217
|
if (options?.readToken) {
|
|
182
218
|
options.readToken().then(
|
|
183
|
-
(
|
|
219
|
+
(code) => {
|
|
184
220
|
if (!settled) {
|
|
185
221
|
settled = true;
|
|
186
222
|
server.close();
|
|
187
|
-
resolve(
|
|
223
|
+
resolve({ code, user: { id: "", email: undefined } });
|
|
188
224
|
}
|
|
189
225
|
},
|
|
190
226
|
() => {
|
|
@@ -229,6 +265,11 @@ export class AuthService {
|
|
|
229
265
|
isSSOAuthenticated(): boolean {
|
|
230
266
|
return this.getSSOToken() !== undefined;
|
|
231
267
|
}
|
|
268
|
+
|
|
269
|
+
getAuthUser(): AuthUser | undefined {
|
|
270
|
+
const config = this.loadAuth();
|
|
271
|
+
return config.user;
|
|
272
|
+
}
|
|
232
273
|
}
|
|
233
274
|
|
|
234
275
|
export const authService = AuthService.getInstance();
|
package/src/telemetry/events.ts
CHANGED
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { OTelEventName } from "../types/telemetry.js";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
isInitialized,
|
|
11
|
+
getCurrentConfig,
|
|
12
|
+
getTelemetryAttributes,
|
|
13
|
+
} from "./instrumentation.js";
|
|
10
14
|
|
|
11
15
|
interface OTelLogger {
|
|
12
16
|
emit: (logRecord: {
|
|
@@ -52,6 +56,10 @@ export async function logOTelEvent(
|
|
|
52
56
|
|
|
53
57
|
log.emit({
|
|
54
58
|
body: eventName,
|
|
55
|
-
attributes: {
|
|
59
|
+
attributes: {
|
|
60
|
+
"event.name": eventName,
|
|
61
|
+
...getTelemetryAttributes(),
|
|
62
|
+
...attributes,
|
|
63
|
+
},
|
|
56
64
|
});
|
|
57
65
|
}
|
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
LogRecordExporter,
|
|
19
19
|
ReadableLogRecord,
|
|
20
20
|
} from "@opentelemetry/sdk-logs";
|
|
21
|
+
import { AuthService } from "../services/authService.js";
|
|
21
22
|
|
|
22
23
|
// Lazy-loaded OTEL modules — only imported when telemetry is initialized
|
|
23
24
|
let sdkNode: typeof import("@opentelemetry/sdk-node") | undefined;
|
|
@@ -468,3 +469,23 @@ export function isInitialized(): boolean {
|
|
|
468
469
|
|
|
469
470
|
// Export JSONL exporters for testing
|
|
470
471
|
export { JsonlSpanExporter, JsonlLogExporter };
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Get telemetry attributes based on the authenticated SSO user.
|
|
475
|
+
* Returns user.id and user.email when SSO authenticated, empty object otherwise.
|
|
476
|
+
*/
|
|
477
|
+
export function getTelemetryAttributes(): Record<string, string> {
|
|
478
|
+
try {
|
|
479
|
+
const user = AuthService.getInstance().getAuthUser();
|
|
480
|
+
if (user) {
|
|
481
|
+
const attrs: Record<string, string> = { "user.id": user.id };
|
|
482
|
+
if (user.email) {
|
|
483
|
+
attrs["user.email"] = user.email;
|
|
484
|
+
}
|
|
485
|
+
return attrs;
|
|
486
|
+
}
|
|
487
|
+
} catch {
|
|
488
|
+
// AuthService not available or not authenticated
|
|
489
|
+
}
|
|
490
|
+
return {};
|
|
491
|
+
}
|
|
@@ -127,7 +127,7 @@ export const toolSearchTool: ToolPlugin = {
|
|
|
127
127
|
name: TOOL_SEARCH_TOOL_NAME,
|
|
128
128
|
description: `Fetches full schema definitions for deferred tools so they can be called.
|
|
129
129
|
|
|
130
|
-
Deferred tools appear by name in <available-deferred-tools> messages.
|
|
130
|
+
Deferred tools appear by name and description in <available-deferred-tools> messages. The full parameter schema is NOT loaded yet — use this tool to fetch it before invoking a deferred tool. This tool takes a query, matches it against the deferred tool list, and returns the matched tools' complete JSONSchema definitions inside a <functions> block. Once a tool's schema appears in that result, it is callable exactly like any tool defined at the top of the prompt.
|
|
131
131
|
|
|
132
132
|
Result format: each matched tool appears as one <function>{"description": "...", "name": "...", "parameters": {...}}`,
|
|
133
133
|
parameters: {
|