@agentuity/coder-tui 3.0.0-alpha.6 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/agentuity-cli.d.ts +12 -0
  2. package/dist/agentuity-cli.d.ts.map +1 -0
  3. package/dist/agentuity-cli.js +178 -0
  4. package/dist/agentuity-cli.js.map +1 -0
  5. package/dist/aigateway.d.ts +4 -0
  6. package/dist/aigateway.d.ts.map +1 -0
  7. package/dist/aigateway.js +178 -0
  8. package/dist/aigateway.js.map +1 -0
  9. package/dist/footer.d.ts +3 -2
  10. package/dist/footer.d.ts.map +1 -1
  11. package/dist/footer.js +50 -16
  12. package/dist/footer.js.map +1 -1
  13. package/dist/hub-overlay-state.d.ts.map +1 -1
  14. package/dist/hub-overlay-state.js +3 -1
  15. package/dist/hub-overlay-state.js.map +1 -1
  16. package/dist/hub-overlay.d.ts.map +1 -1
  17. package/dist/hub-overlay.js +12 -3
  18. package/dist/hub-overlay.js.map +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +53 -30
  22. package/dist/index.js.map +1 -1
  23. package/dist/local-init-filter.d.ts +5 -0
  24. package/dist/local-init-filter.d.ts.map +1 -0
  25. package/dist/local-init-filter.js +40 -0
  26. package/dist/local-init-filter.js.map +1 -0
  27. package/dist/protocol.d.ts +2 -0
  28. package/dist/protocol.d.ts.map +1 -1
  29. package/dist/remote-session.d.ts.map +1 -1
  30. package/dist/remote-session.js +12 -6
  31. package/dist/remote-session.js.map +1 -1
  32. package/dist/renderers.d.ts.map +1 -1
  33. package/dist/renderers.js +53 -1
  34. package/dist/renderers.js.map +1 -1
  35. package/dist/startup-logo.d.ts +3 -0
  36. package/dist/startup-logo.d.ts.map +1 -0
  37. package/dist/startup-logo.js +212 -0
  38. package/dist/startup-logo.js.map +1 -0
  39. package/dist/subagent-tool-selection.d.ts +3 -0
  40. package/dist/subagent-tool-selection.d.ts.map +1 -0
  41. package/dist/subagent-tool-selection.js +22 -0
  42. package/dist/subagent-tool-selection.js.map +1 -0
  43. package/package.json +6 -6
  44. package/src/agentuity-cli.ts +225 -0
  45. package/src/aigateway.ts +256 -0
  46. package/src/footer.ts +62 -15
  47. package/src/hub-overlay-state.ts +4 -1
  48. package/src/hub-overlay.ts +14 -3
  49. package/src/index.ts +59 -32
  50. package/src/local-init-filter.ts +54 -0
  51. package/src/protocol.ts +2 -0
  52. package/src/remote-session.ts +12 -6
  53. package/src/renderers.ts +61 -1
  54. package/src/startup-logo.ts +255 -0
  55. package/src/subagent-tool-selection.ts +33 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"startup-logo.js","sourceRoot":"","sources":["../src/startup-logo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { AgentDefinition } from './protocol.ts';
2
+ export declare function selectSubAgentToolNames(agentConfig: AgentDefinition): string[];
3
+ //# sourceMappingURL=subagent-tool-selection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-tool-selection.d.ts","sourceRoot":"","sources":["../src/subagent-tool-selection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AASrD,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,eAAe,GAAG,MAAM,EAAE,CAuB9E"}
@@ -0,0 +1,22 @@
1
+ const READ_ONLY_TOOL_NAMES = ['read', 'grep', 'find', 'ls'];
2
+ const CODING_TOOL_NAMES = ['read', 'bash', 'edit', 'write'];
3
+ function normalizeToolName(name) {
4
+ return name.trim().toLowerCase();
5
+ }
6
+ export function selectSubAgentToolNames(agentConfig) {
7
+ const declared = new Set((agentConfig.tools ?? [])
8
+ .filter((name) => typeof name === 'string' && name.trim().length > 0)
9
+ .map(normalizeToolName));
10
+ const needsBash = declared.has('bash');
11
+ const baseToolNames = agentConfig.readOnly && !needsBash ? READ_ONLY_TOOL_NAMES : CODING_TOOL_NAMES;
12
+ const allowLegacyFallback = agentConfig.strictToolSelection !== true && agentConfig.source === 'builtin';
13
+ if (declared.size === 0) {
14
+ return allowLegacyFallback ? [...baseToolNames] : [];
15
+ }
16
+ const filtered = baseToolNames.filter((toolName) => declared.has(toolName));
17
+ if (filtered.length > 0) {
18
+ return filtered;
19
+ }
20
+ return allowLegacyFallback ? [...baseToolNames] : [];
21
+ }
22
+ //# sourceMappingURL=subagent-tool-selection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-tool-selection.js","sourceRoot":"","sources":["../src/subagent-tool-selection.ts"],"names":[],"mappings":"AAEA,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAU,CAAC;AACrE,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAU,CAAC;AAErE,SAAS,iBAAiB,CAAC,IAAY;IACtC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,WAA4B;IACnE,MAAM,QAAQ,GAAG,IAAI,GAAG,CACvB,CAAC,WAAW,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;SACpF,GAAG,CAAC,iBAAiB,CAAC,CACxB,CAAC;IACF,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,aAAa,GAClB,WAAW,CAAC,QAAQ,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAC/E,MAAM,mBAAmB,GACxB,WAAW,CAAC,mBAAmB,KAAK,IAAI,IAAI,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC;IAE9E,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE5E,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACtD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentuity/coder-tui",
3
- "version": "3.0.0-alpha.6",
3
+ "version": "3.0.0-beta.0",
4
4
  "description": "Agentuity Coder Hub extension for Pi coding agent",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Agentuity employees and contributors",
@@ -25,12 +25,12 @@
25
25
  "prepublishOnly": "bun run clean && bun run build"
26
26
  },
27
27
  "dependencies": {
28
- "@mariozechner/pi-coding-agent": "^0.65.0",
29
- "@mariozechner/pi-tui": "^0.65.0",
30
- "@sinclair/typebox": "^0.34.48"
28
+ "@mariozechner/pi-coding-agent": "^0.72.1",
29
+ "@mariozechner/pi-tui": "^0.72.1",
30
+ "@sinclair/typebox": "^0.34.49"
31
31
  },
32
32
  "devDependencies": {
33
- "@mariozechner/pi-ai": "^0.65.0",
33
+ "@mariozechner/pi-ai": "^0.70.2",
34
34
  "@types/bun": "^1.3.9",
35
35
  "bun-types": "^1.3.9",
36
36
  "typescript": "^5.9.0"
@@ -41,7 +41,7 @@
41
41
  "sideEffects": false,
42
42
  "repository": {
43
43
  "type": "git",
44
- "url": "https://github.com/agentuity/sdk.git",
44
+ "url": "git+https://github.com/agentuity/sdk.git",
45
45
  "directory": "packages/coder-tui"
46
46
  }
47
47
  }
@@ -0,0 +1,225 @@
1
+ const SHELL_ASSIGNMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|\S+)$/;
2
+
3
+ export const AGENTUITY_CLI_MARK = '⨺';
4
+
5
+ type ToolArgsInput = string | Record<string, unknown> | undefined;
6
+
7
+ export interface ToolDisplayDescriptor {
8
+ toolName: string;
9
+ toolArgs?: string;
10
+ fullLabel: string;
11
+ branded: boolean;
12
+ }
13
+
14
+ function stripShellQuotes(value: string): string {
15
+ if (
16
+ (value.startsWith('"') && value.endsWith('"')) ||
17
+ (value.startsWith("'") && value.endsWith("'"))
18
+ ) {
19
+ return value.slice(1, -1);
20
+ }
21
+ return value;
22
+ }
23
+
24
+ function tokenizeShellLike(command: string): string[] {
25
+ return (command.match(/"(?:\\.|[^"])*"|'(?:\\.|[^'])*'|&&|\|\||[;|()]|[^\s;|()]+/g) ?? []).map(
26
+ stripShellQuotes
27
+ );
28
+ }
29
+
30
+ function splitShellSegments(command: string): string[] {
31
+ return command
32
+ .split(/(?:\r?\n|&&|\|\||;|\|)/)
33
+ .map((segment) => segment.trim())
34
+ .filter(Boolean);
35
+ }
36
+
37
+ function optionConsumesValue(token: string): boolean {
38
+ return (
39
+ token === '-c' ||
40
+ token === '-g' ||
41
+ token === '-h' ||
42
+ token === '-p' ||
43
+ token === '-r' ||
44
+ token === '-t' ||
45
+ token === '-u' ||
46
+ token === '--chdir' ||
47
+ token === '--config' ||
48
+ token === '--group' ||
49
+ token === '--host' ||
50
+ token === '--package' ||
51
+ token === '--registry' ||
52
+ token === '--user'
53
+ );
54
+ }
55
+
56
+ function trimShellPrefix(tokens: string[]): string[] {
57
+ let index = 0;
58
+
59
+ while (index < tokens.length) {
60
+ const token = tokens[index];
61
+ if (!token || token === '!' || token === '(' || token === ')') {
62
+ index += 1;
63
+ continue;
64
+ }
65
+
66
+ if (token === 'env' || token === 'sudo') {
67
+ index += 1;
68
+ while (tokens[index]?.startsWith('-')) {
69
+ const option = tokens[index] ?? '';
70
+ index += optionConsumesValue(option) ? 2 : 1;
71
+ }
72
+ continue;
73
+ }
74
+
75
+ if (SHELL_ASSIGNMENT_PATTERN.test(token)) {
76
+ index += 1;
77
+ continue;
78
+ }
79
+
80
+ break;
81
+ }
82
+
83
+ return tokens.slice(index);
84
+ }
85
+
86
+ function extractAgentuityCliRemainderFromTokens(tokens: string[]): string | null {
87
+ const trimmed = trimShellPrefix(tokens);
88
+ if (trimmed.length === 0) return null;
89
+
90
+ const first = trimmed[0]?.toLowerCase();
91
+ if (first === 'agentuity') {
92
+ return trimmed.slice(1).join(' ').trim();
93
+ }
94
+
95
+ if (first === 'bunx' || first === 'npx') {
96
+ let index = 1;
97
+ while (trimmed[index]?.startsWith('-')) {
98
+ const option = trimmed[index] ?? '';
99
+ index += optionConsumesValue(option) ? 2 : 1;
100
+ }
101
+ if (trimmed[index] === '@agentuity/cli') {
102
+ return trimmed
103
+ .slice(index + 1)
104
+ .join(' ')
105
+ .trim();
106
+ }
107
+ }
108
+
109
+ if (first === 'pnpm' && trimmed[1]?.toLowerCase() === 'dlx') {
110
+ let index = 2;
111
+ while (trimmed[index]?.startsWith('-')) {
112
+ const option = trimmed[index] ?? '';
113
+ index += optionConsumesValue(option) ? 2 : 1;
114
+ }
115
+ if (trimmed[index] === '@agentuity/cli') {
116
+ return trimmed
117
+ .slice(index + 1)
118
+ .join(' ')
119
+ .trim();
120
+ }
121
+ }
122
+
123
+ return null;
124
+ }
125
+
126
+ function normalizeDisplayWhitespace(value: string): string {
127
+ return value.replace(/\s+/g, ' ').trim();
128
+ }
129
+
130
+ function trimDisplay(value: string, max: number): string {
131
+ const normalized = normalizeDisplayWhitespace(value);
132
+ if (normalized.length <= max) return normalized;
133
+ return `${normalized.slice(0, max - 3)}...`;
134
+ }
135
+
136
+ function getCommandArg(rawArgs?: ToolArgsInput): string | undefined {
137
+ if (typeof rawArgs === 'string' && rawArgs.trim()) {
138
+ return rawArgs.trim();
139
+ }
140
+
141
+ if (!rawArgs || typeof rawArgs !== 'object') {
142
+ return undefined;
143
+ }
144
+
145
+ const value = rawArgs.command ?? rawArgs.cmd;
146
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
147
+ }
148
+
149
+ function getGenericToolArgsPreview(rawArgs?: ToolArgsInput): string | undefined {
150
+ if (typeof rawArgs === 'string' && rawArgs.trim()) {
151
+ return trimDisplay(rawArgs.trim(), 60);
152
+ }
153
+
154
+ if (!rawArgs || typeof rawArgs !== 'object') {
155
+ return undefined;
156
+ }
157
+
158
+ if (typeof rawArgs.command === 'string' && rawArgs.command.trim()) {
159
+ return trimDisplay(rawArgs.command.trim(), 60);
160
+ }
161
+ if (typeof rawArgs.filePath === 'string' && rawArgs.filePath.trim()) {
162
+ return rawArgs.filePath.trim();
163
+ }
164
+ if (typeof rawArgs.path === 'string' && rawArgs.path.trim()) {
165
+ return rawArgs.path.trim();
166
+ }
167
+ if (typeof rawArgs.pattern === 'string' && rawArgs.pattern.trim()) {
168
+ return trimDisplay(rawArgs.pattern.trim(), 40);
169
+ }
170
+
171
+ const first = Object.values(rawArgs)[0];
172
+ if (typeof first === 'string' && first.trim()) {
173
+ return trimDisplay(first.trim(), 40);
174
+ }
175
+
176
+ return undefined;
177
+ }
178
+
179
+ function isCommandToolName(toolName: string): boolean {
180
+ const normalized = toolName.trim().toLowerCase();
181
+ return normalized === 'bash' || normalized === 'execute_command' || normalized.includes('shell');
182
+ }
183
+
184
+ export function getAgentuityCliCommandRemainder(command?: string): string | null {
185
+ if (!command?.trim()) return null;
186
+
187
+ for (const segment of splitShellSegments(command)) {
188
+ const remainder = extractAgentuityCliRemainderFromTokens(tokenizeShellLike(segment));
189
+ if (remainder !== null) {
190
+ return remainder;
191
+ }
192
+ }
193
+
194
+ return null;
195
+ }
196
+
197
+ export function formatToolDisplay(
198
+ toolName: string,
199
+ rawArgs?: ToolArgsInput
200
+ ): ToolDisplayDescriptor {
201
+ const normalizedToolName = normalizeDisplayWhitespace(toolName) || 'tool';
202
+ const command = getCommandArg(rawArgs);
203
+
204
+ if (isCommandToolName(normalizedToolName) && command) {
205
+ const remainder = getAgentuityCliCommandRemainder(command);
206
+ if (remainder !== null) {
207
+ const brandedToolName = `${AGENTUITY_CLI_MARK} agentuity`;
208
+ const toolArgs = remainder ? trimDisplay(remainder, 60) : undefined;
209
+ return {
210
+ toolName: brandedToolName,
211
+ toolArgs,
212
+ fullLabel: toolArgs ? `${brandedToolName} ${toolArgs}` : brandedToolName,
213
+ branded: true,
214
+ };
215
+ }
216
+ }
217
+
218
+ const toolArgs = getGenericToolArgsPreview(rawArgs);
219
+ return {
220
+ toolName: normalizedToolName,
221
+ toolArgs,
222
+ fullLabel: toolArgs ? `${normalizedToolName} ${toolArgs}` : normalizedToolName,
223
+ branded: false,
224
+ };
225
+ }
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Agentuity AI Gateway Custom Provider Extension
3
+ *
4
+ * Registers models from the Agentuity AI Gateway using the appropriate API type
5
+ * based on model ID patterns. Models are loaded dynamically from the gateway's /models endpoint.
6
+ *
7
+ * Usage:
8
+ * Use /model to switch to aigateway models
9
+ */
10
+ import { delimiter, join } from 'node:path';
11
+ import { existsSync } from 'node:fs';
12
+ import { execFileSync } from 'node:child_process';
13
+ import type { ExtensionAPI, ProviderModelConfig } from '@mariozechner/pi-coding-agent';
14
+
15
+ export type KnownApi =
16
+ | 'openai-completions'
17
+ | 'mistral-conversations'
18
+ | 'openai-responses'
19
+ | 'azure-openai-responses'
20
+ | 'openai-codex-responses'
21
+ | 'anthropic-messages'
22
+ | 'bedrock-converse-stream'
23
+ | 'google-generative-ai'
24
+ | 'google-gemini-cli'
25
+ | 'google-vertex';
26
+
27
+ const MODEL_CATALOG_TIMEOUT_MS = 5_000;
28
+
29
+ const KNOWN_APIS = new Set<string>([
30
+ 'openai-completions',
31
+ 'mistral-conversations',
32
+ 'openai-responses',
33
+ 'azure-openai-responses',
34
+ 'openai-codex-responses',
35
+ 'anthropic-messages',
36
+ 'bedrock-converse-stream',
37
+ 'google-generative-ai',
38
+ 'google-gemini-cli',
39
+ 'google-vertex',
40
+ ] satisfies KnownApi[]);
41
+
42
+ interface AIGatewayModels {
43
+ [key: string]: AIGatewayModel[];
44
+ }
45
+
46
+ interface AIGatewayModelResponse {
47
+ success: boolean;
48
+ data: AIGatewayModels;
49
+ message?: string;
50
+ error?: string;
51
+ }
52
+
53
+ interface AIGatewayModel {
54
+ id: string;
55
+ name: string;
56
+ api: KnownApi;
57
+ reasoning: boolean;
58
+ input_modalities?: ('text' | 'image')[];
59
+ context_window?: number;
60
+ max_output_tokens?: number;
61
+ pricing?: {
62
+ input: number;
63
+ output: number;
64
+ cached_input: number;
65
+ unit: 'per_million_tokens';
66
+ currency: 'USD';
67
+ };
68
+ }
69
+
70
+ function getEnv(...keys: string[]): string | undefined {
71
+ for (const key of keys) {
72
+ if (process.env[key]) {
73
+ return process.env[key];
74
+ }
75
+ }
76
+ }
77
+
78
+ function normalizeCredential(value: unknown): string | undefined {
79
+ if (value === undefined || value === null) {
80
+ return undefined;
81
+ }
82
+ const normalized = String(value).trim();
83
+ return normalized.length > 0 ? normalized : undefined;
84
+ }
85
+
86
+ function isKnownApi(api: unknown): api is KnownApi {
87
+ return typeof api === 'string' && KNOWN_APIS.has(api);
88
+ }
89
+
90
+ function getRegion(): string {
91
+ return getEnv('AGENTUITY_REGION') ?? 'usc';
92
+ }
93
+
94
+ function getBaseUrl(): string {
95
+ const region = getRegion();
96
+ return `https://aigateway-${region}.agentuity.cloud`;
97
+ }
98
+
99
+ async function fetchModels(): Promise<AIGatewayModels> {
100
+ const baseUrl = getBaseUrl();
101
+ let apiKey = normalizeCredential(
102
+ getEnv(
103
+ 'AGENTUITY_CODER_API_KEY',
104
+ 'AGENTUITY_SDK_KEY',
105
+ 'AGENTUITY_CLI_API_KEY',
106
+ 'AGENTUITY_CLI_KEY'
107
+ )
108
+ );
109
+ let orgId = normalizeCredential(
110
+ getEnv('AGENTUITY_ORGID', 'AGENTUITY_CLOUD_ORG_ID', 'AGENTUITY_ORG_ID')
111
+ );
112
+
113
+ if (!apiKey) {
114
+ let found = false;
115
+ const path = process.env.PATH?.split(delimiter) ?? [];
116
+ for (const dir of path) {
117
+ const fn = join(dir, 'agentuity');
118
+ if (existsSync(fn)) {
119
+ try {
120
+ const res = execFileSync(fn, ['auth', 'apikey', '--json']);
121
+ const apiKeyResult = JSON.parse(res.toString()) as { apiKey: string };
122
+ apiKey = normalizeCredential(apiKeyResult.apiKey);
123
+ found = true;
124
+ if (!orgId) {
125
+ const ores = execFileSync(fn, ['auth', 'org', 'current']);
126
+ orgId = normalizeCredential(ores);
127
+ if (!orgId) {
128
+ console.warn(
129
+ 'Cannot determine the org id. Use `agentuity auth org select` to select a default organization'
130
+ );
131
+ return {};
132
+ }
133
+ }
134
+ break;
135
+ } catch (_ex) {
136
+ //
137
+ }
138
+ }
139
+ }
140
+ if (!found) {
141
+ console.warn(
142
+ 'AGENTUITY_SDK_KEY, AGENTUITY_CLI_API_KEY or AGENTUITY_CLI_KEY not set and cannot find the agentuit cli, cannot fetch models from AI Gateway'
143
+ );
144
+ return {};
145
+ }
146
+ }
147
+
148
+ if (!apiKey) {
149
+ console.warn('Cannot determine the API key, cannot fetch models from AI Gateway');
150
+ return {};
151
+ }
152
+
153
+ process.env.AGENTUITY_AIGATEWAY_KEY = apiKey;
154
+ if (orgId) {
155
+ process.env.AGENTUITY_AIGATEWAY_ORGID = orgId;
156
+ }
157
+
158
+ const controller = new AbortController();
159
+ const timeout = setTimeout(() => controller.abort(), MODEL_CATALOG_TIMEOUT_MS);
160
+
161
+ try {
162
+ const response = await fetch(`${baseUrl}/models`, { signal: controller.signal });
163
+
164
+ if (!response.ok) {
165
+ console.warn(
166
+ `Failed to fetch models from AI Gateway: ${response.status} ${response.statusText}`
167
+ );
168
+ return {};
169
+ }
170
+
171
+ const payload = (await response.json()) as AIGatewayModelResponse;
172
+
173
+ if (!payload.success) {
174
+ console.warn(`Failed to load models. ${payload.message} ${payload}`);
175
+ }
176
+
177
+ return payload.data;
178
+ } catch (error) {
179
+ if (error instanceof Error && error.name === 'AbortError') {
180
+ console.warn(
181
+ `Timed out fetching models from AI Gateway after ${MODEL_CATALOG_TIMEOUT_MS}ms`
182
+ );
183
+ return {};
184
+ }
185
+ console.warn('Failed to fetch models from AI Gateway:', error);
186
+ return {};
187
+ } finally {
188
+ clearTimeout(timeout);
189
+ }
190
+ }
191
+
192
+ function toPiModel(m: AIGatewayModel): ProviderModelConfig {
193
+ return {
194
+ id: m.id,
195
+ name: m.name,
196
+ reasoning: m.reasoning,
197
+ input: m.input_modalities as ('text' | 'image')[],
198
+ contextWindow: m.context_window ?? 40000,
199
+ maxTokens: m.max_output_tokens ?? 64000,
200
+ cost: {
201
+ input: m.pricing?.input ?? 0,
202
+ output: m.pricing?.output ?? 0,
203
+ cacheRead: m.pricing?.cached_input ?? 0,
204
+ cacheWrite: 0,
205
+ },
206
+ compat: {
207
+ supportsDeveloperRole: false,
208
+ },
209
+ };
210
+ }
211
+
212
+ export async function setupAIGateway(pi: ExtensionAPI) {
213
+ const models = await fetchModels();
214
+ const baseUrl = getBaseUrl();
215
+
216
+ const allModels: AIGatewayModel[] = [];
217
+ for (const providerModels of Object.values(models)) {
218
+ if (providerModels) {
219
+ allModels.push(...providerModels);
220
+ }
221
+ }
222
+ if (allModels.length === 0) {
223
+ return;
224
+ }
225
+
226
+ const modelsByApi = new Map<KnownApi, ProviderModelConfig[]>();
227
+
228
+ for (const m of allModels) {
229
+ const apiType = m.api;
230
+ if (!isKnownApi(apiType)) {
231
+ continue; // THIS SHOULD NEVER HAPPEN BUT JUST IN CASE
232
+ }
233
+ const existing = modelsByApi.get(apiType) ?? [];
234
+ existing.push(toPiModel(m));
235
+ modelsByApi.set(apiType, existing);
236
+ }
237
+
238
+ const headers: Record<string, string> = {};
239
+ if (process.env.AGENTUITY_AIGATEWAY_ORGID) {
240
+ headers['x-agentuity-orgid'] = process.env.AGENTUITY_AIGATEWAY_ORGID;
241
+ }
242
+
243
+ for (const [apiType, providerModels] of modelsByApi) {
244
+ const apitok = apiType.split('-');
245
+ const name = apitok.length >= 2 ? apitok.slice(0, 2).join('-') : apitok[0];
246
+ const providerName = `agentuity/${name}`;
247
+ pi.registerProvider(providerName, {
248
+ baseUrl,
249
+ apiKey: 'AGENTUITY_AIGATEWAY_KEY',
250
+ headers,
251
+ authHeader: true,
252
+ api: apiType,
253
+ models: providerModels,
254
+ });
255
+ }
256
+ }
package/src/footer.ts CHANGED
@@ -11,7 +11,11 @@
11
11
  * [3] SwiftRaven — 3 observers watching, session label "SwiftRaven"
12
12
  */
13
13
 
14
- import type { ExtensionContext, ReadonlyFooterDataProvider } from '@mariozechner/pi-coding-agent';
14
+ import type {
15
+ ExtensionAPI,
16
+ ExtensionContext,
17
+ ReadonlyFooterDataProvider,
18
+ } from '@mariozechner/pi-coding-agent';
15
19
 
16
20
  const RESET = '\x1b[0m';
17
21
  const SEP = '>';
@@ -185,42 +189,85 @@ function formatCost(n: number): string {
185
189
  *
186
190
  * Includes a braille spinner animation when an agent is actively working.
187
191
  *
192
+ * @param pi Extension API
188
193
  * @param ctx Extension context with UI access
189
194
  * @param getHubStatus Callback that returns current Hub connection status
190
195
  * @param getObserverState Optional callback that returns observer count + session label
191
196
  */
192
197
  export function setupCoderFooter(
198
+ pi: ExtensionAPI,
193
199
  ctx: ExtensionContext,
194
200
  getHubStatus: () => HubStatus,
195
201
  getObserverState?: () => ObserverState
196
202
  ): void {
197
203
  if (!ctx.hasUI) return;
198
204
 
205
+ ctx.ui.setWorkingIndicator({ frames: [] }); // turn off the working indicator since we use our own spinner
206
+
207
+ let pendingRequests = 0;
208
+ let spinnerTimer: ReturnType<typeof setInterval> | null = null;
209
+ let spinnerFrame = 0;
210
+ let activeAgentRunning = false;
211
+ let requestFooterRender: (() => void) | undefined;
212
+
213
+ const startSpinner = () => {
214
+ if (spinnerTimer) return;
215
+ spinnerTimer = setInterval(() => {
216
+ spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES.length;
217
+ requestFooterRender?.();
218
+ }, 80);
219
+ };
220
+
221
+ const stopSpinner = () => {
222
+ if (!spinnerTimer) return;
223
+ clearInterval(spinnerTimer);
224
+ spinnerTimer = null;
225
+ spinnerFrame = 0;
226
+ };
227
+
228
+ const syncSpinner = () => {
229
+ if (pendingRequests > 0 || activeAgentRunning) {
230
+ startSpinner();
231
+ } else {
232
+ stopSpinner();
233
+ }
234
+ };
235
+
236
+ pi.on('before_provider_request', () => {
237
+ pendingRequests += 1;
238
+ if (pendingRequests === 1) {
239
+ startSpinner();
240
+ }
241
+ });
242
+
243
+ pi.on('after_provider_response', () => {
244
+ pendingRequests = Math.max(0, pendingRequests - 1);
245
+ syncSpinner();
246
+ });
247
+
248
+ pi.on('session_shutdown', () => {
249
+ pendingRequests = 0;
250
+ activeAgentRunning = false;
251
+ stopSpinner();
252
+ });
253
+
199
254
  ctx.ui.setFooter((tui, _theme, footerData) => {
200
- // Spinner state
201
- let spinnerTimer: ReturnType<typeof setInterval> | null = null;
202
- let spinnerFrame = 0;
255
+ requestFooterRender = () => tui.requestRender();
203
256
 
204
257
  const getText = (width: number): string => {
205
258
  // Detect active agent
206
259
  const activeAgent = footerData.getExtensionStatuses().get('active_agent');
207
260
 
208
- // Start/stop spinner based on agent activity
209
- if (activeAgent && !spinnerTimer) {
210
- spinnerTimer = setInterval(() => {
211
- spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES.length;
212
- tui.requestRender();
213
- }, 80);
214
- } else if (!activeAgent && spinnerTimer) {
215
- clearInterval(spinnerTimer);
216
- spinnerTimer = null;
217
- spinnerFrame = 0;
218
- }
261
+ activeAgentRunning = !!activeAgent;
262
+ syncSpinner();
219
263
 
220
264
  // Token stats from session messages
221
265
  let inputTokens = 0;
222
266
  let outputTokens = 0;
223
267
  let totalCost = 0;
268
+
269
+ // TODO (jhaynie): we need to think about how to handle our AI Gateway costs vs whats coming from pi
270
+
224
271
  for (const entry of ctx.sessionManager.getBranch()) {
225
272
  if (entry.type === 'message') {
226
273
  const msg = entry.message as {