Skip to content

Commit a4acbcf

Browse files
committed
loading
1 parent ffcc184 commit a4acbcf

File tree

11 files changed

+116
-15
lines changed

11 files changed

+116
-15
lines changed

ts/packages/agentSdk/src/agentInterface.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,13 @@ export type SchemaTypeNames = {
4848
};
4949

5050
export type SchemaFormat = "ts" | "pas";
51+
export type GrammarFormat = "ag";
52+
5153
export type SchemaManifest = {
5254
description: string;
5355
schemaType: string | SchemaTypeNames; // string if there are only action schemas
5456
schemaFile: string | { format: SchemaFormat; content: string };
57+
grammarFile?: string | { format: GrammarFormat; content: string };
5558
injected?: boolean; // whether the translator is injected into other domains, default is false
5659
cached?: boolean; // whether the translator's action should be cached, default is true
5760
streamingActions?: string[];

ts/packages/agentSdk/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
export {
55
AppAgentManifest,
66
ActionManifest,
7+
GrammarFormat,
78
SchemaFormat,
89
SchemaManifest,
910
AppAgent,

ts/packages/cache/src/cache/cache.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,24 @@ function getFailedResult(message: string): ProcessRequestActionResult {
5858
},
5959
};
6060
}
61+
62+
export function getSchemaNamespaceKey(
63+
name: string,
64+
activityName: string | undefined,
65+
schemaInfoProvider: SchemaInfoProvider | undefined,
66+
) {
67+
return `${name},${schemaInfoProvider?.getActionSchemaFileHash(name) ?? ""},${activityName ?? ""}`;
68+
}
69+
6170
// Namespace policy. Combines schema name, file hash, and activity name to indicate enabling/disabling of matching.
6271
export function getSchemaNamespaceKeys(
6372
schemaNames: string[],
6473
activityName: string | undefined,
6574
schemaInfoProvider: SchemaInfoProvider | undefined,
6675
) {
6776
// Current namespace keys policy is just combining schema name its file hash
68-
return schemaNames.map(
69-
(name) =>
70-
`${name},${schemaInfoProvider?.getActionSchemaFileHash(name) ?? ""},${activityName ?? ""}`,
77+
return schemaNames.map((name) =>
78+
getSchemaNamespaceKey(name, activityName, schemaInfoProvider),
7179
);
7280
}
7381

@@ -99,7 +107,7 @@ export class AgentCache {
99107
cacheOptions?: CacheOptions,
100108
logger?: Telemetry.Logger,
101109
) {
102-
this._grammarStore = new GrammarStoreImpl();
110+
this._grammarStore = new GrammarStoreImpl(schemaInfoProvider);
103111
this._constructionStore = new ConstructionStoreImpl(
104112
explainerName,
105113
cacheOptions,
@@ -129,7 +137,6 @@ export class AgentCache {
129137
public get grammarStore(): GrammarStore {
130138
return this._grammarStore;
131139
}
132-
133140
public get constructionStore(): ConstructionStore {
134141
return this._constructionStore;
135142
}

ts/packages/cache/src/cache/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ export type MatchResult = {
1616

1717
export interface GrammarStore {
1818
addGrammar(namespace: string, grammar: any): void;
19+
removeGrammar(namespace: string): void;
1920
}

ts/packages/cache/src/grammar/grammarStore.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,29 @@
44
import { Grammar, matchGrammar } from "action-grammar";
55
import { MatchOptions } from "../constructions/constructionCache.js";
66
import { MatchResult, GrammarStore } from "../cache/types.js";
7+
import { getSchemaNamespaceKey } from "../cache/cache.js";
8+
import { SchemaInfoProvider } from "../explanation/schemaInfoProvider.js";
79

810
export class GrammarStoreImpl implements GrammarStore {
911
private readonly grammars: Map<string, any> = new Map();
10-
public addGrammar(namespace: string, grammar: Grammar): void {
11-
this.grammars.set(namespace, grammar);
12+
public constructor(
13+
private readonly schemaInfoProvider: SchemaInfoProvider | undefined,
14+
) {}
15+
public addGrammar(schemaName: string, grammar: Grammar): void {
16+
const namespaceKey = getSchemaNamespaceKey(
17+
schemaName,
18+
undefined,
19+
this.schemaInfoProvider,
20+
);
21+
this.grammars.set(namespaceKey, grammar);
22+
}
23+
public removeGrammar(schemaName: string): void {
24+
const namespaceKey = getSchemaNamespaceKey(
25+
schemaName,
26+
undefined,
27+
this.schemaInfoProvider,
28+
);
29+
this.grammars.delete(namespaceKey);
1230
}
1331
public match(request: string, options?: MatchOptions): MatchResult[] {
1432
const namespaceKeys = options?.namespaceKeys;

ts/packages/dispatcher/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"@azure/identity": "^4.10.0",
4848
"@azure/msal-node-extensions": "^1.5.0",
4949
"@typeagent/agent-sdk": "workspace:*",
50+
"action-grammar": "workspace:*",
5051
"action-schema": "workspace:*",
5152
"agent-cache": "workspace:*",
5253
"agent-rpc": "workspace:*",

ts/packages/dispatcher/src/context/appAgentManager.ts

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ import {
3232
AppAgentStateConfig,
3333
appAgentStateKeys,
3434
} from "./appAgentStateConfig.js";
35+
import { GrammarStore } from "../../../cache/dist/cache/types.js";
36+
import { getPackageFilePath } from "../utils/getPackageFilePath.js";
37+
import fs from "node:fs";
38+
import { Grammar, grammarFromJson } from "action-grammar";
3539

3640
const debug = registerDebug("typeagent:dispatcher:agents");
3741
const debugError = registerDebug("typeagent:dispatcher:agents:error");
@@ -91,6 +95,32 @@ export const alwaysEnabledAgents = {
9195
commands: ["system"],
9296
};
9397

98+
function loadGrammar(actionConfig: ActionConfig): Grammar | undefined {
99+
if (actionConfig.grammarFile === undefined) {
100+
return undefined;
101+
}
102+
103+
let source: string;
104+
if (typeof actionConfig.grammarFile === "string") {
105+
const fullPath = getPackageFilePath(actionConfig.grammarFile);
106+
source = fs.readFileSync(fullPath, "utf-8");
107+
const isActionGrammar = actionConfig.grammarFile.endsWith(".ag.json");
108+
if (!isActionGrammar) {
109+
throw new Error(
110+
`Unsupported grammar file extension: ${actionConfig.grammarFile}`,
111+
);
112+
}
113+
} else {
114+
if (actionConfig.grammarFile.format !== "ag") {
115+
throw new Error(
116+
`Unsupported grammar file extension: ${actionConfig.grammarFile}`,
117+
);
118+
}
119+
source = actionConfig.grammarFile.content;
120+
}
121+
return grammarFromJson(JSON.parse(source));
122+
}
123+
94124
export class AppAgentManager implements ActionConfigProvider {
95125
private readonly agents = new Map<string, AppAgentRecord>();
96126
private readonly actionConfigs = new Map<string, ActionConfig>();
@@ -237,6 +267,7 @@ export class AppAgentManager implements ActionConfigProvider {
237267

238268
public async addProvider(
239269
provider: AppAgentProvider,
270+
actionGrammarStore: GrammarStore | undefined,
240271
actionEmbeddingCache?: EmbeddingCache,
241272
) {
242273
const semanticMapP: Promise<void>[] = [];
@@ -246,6 +277,8 @@ export class AppAgentManager implements ActionConfigProvider {
246277
name,
247278
manifest,
248279
semanticMapP,
280+
281+
actionGrammarStore,
249282
provider,
250283
actionEmbeddingCache,
251284
);
@@ -259,6 +292,7 @@ export class AppAgentManager implements ActionConfigProvider {
259292
appAgentName: string,
260293
manifest: AppAgentManifest,
261294
semanticMapP: Promise<void>[],
295+
actionGrammarStore: GrammarStore | undefined,
262296
provider?: AppAgentProvider,
263297
actionEmbeddingCache?: EmbeddingCache,
264298
) {
@@ -289,6 +323,17 @@ export class AppAgentManager implements ActionConfigProvider {
289323
),
290324
);
291325
}
326+
327+
if (actionGrammarStore) {
328+
try {
329+
const g = loadGrammar(config);
330+
if (g) {
331+
actionGrammarStore.addGrammar(schemaName, g);
332+
}
333+
} catch {
334+
// REVIEW: Ignore errors for now.
335+
}
336+
}
292337
} catch (e: any) {
293338
schemaErrors.set(schemaName, e);
294339
}
@@ -321,6 +366,7 @@ export class AppAgentManager implements ActionConfigProvider {
321366
appAgentName: string,
322367
manifest: AppAgentManifest,
323368
appAgent: AppAgent,
369+
actionGrammarStore?: GrammarStore,
324370
) {
325371
if (this.agents.has(appAgentName)) {
326372
throw new Error(`App agent '${appAgentName}' already exists`);
@@ -332,6 +378,7 @@ export class AppAgentManager implements ActionConfigProvider {
332378
appAgentName,
333379
manifest,
334380
semanticMapP,
381+
actionGrammarStore,
335382
);
336383
record.appAgent = appAgent;
337384

@@ -340,7 +387,7 @@ export class AppAgentManager implements ActionConfigProvider {
340387
debug("Finish action embeddings");
341388
}
342389

343-
private cleanupAgent(appAgentName: string) {
390+
private cleanupAgent(appAgentName: string, grammarStore?: GrammarStore) {
344391
for (const [schemaName, config] of this.actionConfigs) {
345392
if (getAppAgentName(schemaName) !== appAgentName) {
346393
continue;
@@ -351,13 +398,19 @@ export class AppAgentManager implements ActionConfigProvider {
351398
if (config.transient) {
352399
delete this.transientAgents[schemaName];
353400
}
401+
if (grammarStore) {
402+
grammarStore.removeGrammar(schemaName);
403+
}
354404
}
355405
}
356406

357-
public async removeAgent(appAgentName: string) {
407+
public async removeAgent(
408+
appAgentName: string,
409+
grammarStore?: GrammarStore,
410+
) {
358411
const record = this.getRecord(appAgentName);
359412
this.agents.delete(appAgentName);
360-
this.cleanupAgent(appAgentName);
413+
this.cleanupAgent(appAgentName, grammarStore);
361414

362415
await this.closeSessionContext(record);
363416
if (record.appAgent !== undefined) {

ts/packages/dispatcher/src/context/commandHandlerContext.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,19 @@ async function addAppAgentProviders(
319319
}
320320

321321
const inlineAppProvider = createBuiltinAppAgentProvider(context);
322-
await context.agents.addProvider(inlineAppProvider, embeddingCache);
322+
await context.agents.addProvider(
323+
inlineAppProvider,
324+
context.agentCache.grammarStore,
325+
embeddingCache,
326+
);
323327

324328
if (appAgentProviders) {
325329
for (const provider of appAgentProviders) {
326-
await context.agents.addProvider(provider, embeddingCache);
330+
await context.agents.addProvider(
331+
provider,
332+
context.agentCache.grammarStore,
333+
embeddingCache,
334+
);
327335
}
328336
}
329337
if (embeddingCachePath) {
@@ -361,7 +369,7 @@ export async function installAppProvider(
361369
provider: AppAgentProvider,
362370
) {
363371
// Don't use embedding cache for a new agent.
364-
await context.agents.addProvider(provider);
372+
await context.agents.addProvider(provider, context.agentCache.grammarStore);
365373

366374
await setAppAgentStates(context);
367375

ts/packages/dispatcher/src/context/system/handlers/installCommandHandlers.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ export class UninstallCommandHandler implements CommandHandler {
8282
const name = params.args.name;
8383
installer.uninstall(name);
8484

85-
await systemContext.agents.removeAgent(name);
85+
await systemContext.agents.removeAgent(
86+
name,
87+
systemContext.agentCache.grammarStore,
88+
);
8689

8790
displayResult(`Agent '${name}' uninstalled.`, context);
8891
}

ts/packages/dispatcher/src/execute/sessionContext.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,10 @@ export function createSessionContext<T = unknown>(
6161
`Permission denied: dynamic agent '${agentName}' not added by this agent`,
6262
);
6363
}
64-
return context.agents.removeAgent(agentName);
64+
return context.agents.removeAgent(
65+
agentName,
66+
context.agentCache.grammarStore,
67+
);
6568
})
6669
: () => {
6770
throw new Error("Permission denied: cannot remove dynamic agent");

0 commit comments

Comments
 (0)