Skip to content

Commit a38fb31

Browse files
committed
Add 0.0.39 backwards compatibility middleware
1 parent 1250c52 commit a38fb31

File tree

4 files changed

+87
-7
lines changed

4 files changed

+87
-7
lines changed

sdks/typescript/packages/client/src/__tests__/parse-semver.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ import { parseSemanticVersion } from "../utils";
33
describe("parseSemanticVersion", () => {
44
it("parses full semantic versions", () => {
55
const parsed = parseSemanticVersion("1.2.3");
6-
expect(parsed).toEqual({
6+
expect(parsed).toMatchObject({
77
major: 1,
88
minor: 2,
99
patch: 3,
1010
prerelease: [],
1111
build: [],
1212
source: "1.2.3",
1313
});
14+
expect(parsed.compare(parsed)).toBe(0);
1415
});
1516

1617
it("defaults missing segments to zero", () => {
@@ -20,14 +21,15 @@ describe("parseSemanticVersion", () => {
2021

2122
it("parses prerelease and build metadata", () => {
2223
const parsed = parseSemanticVersion("2.0.1-alpha.1+build.5");
23-
expect(parsed).toEqual({
24+
expect(parsed).toMatchObject({
2425
major: 2,
2526
minor: 0,
2627
patch: 1,
2728
prerelease: ["alpha", "1"],
2829
build: ["build", "5"],
2930
source: "2.0.1-alpha.1+build.5",
3031
});
32+
expect(parsed.compare(parseSemanticVersion("2.0.1-alpha.2"))).toBeLessThan(0);
3133
});
3234

3335
it("rejects non-semantic labels like latest", () => {

sdks/typescript/packages/client/src/agent/agent.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ import { lastValueFrom } from "rxjs";
1414
import { transformChunks } from "@/chunks";
1515
import { AgentStateMutation, AgentSubscriber, runSubscribersWithMutation } from "./subscriber";
1616
import { AGUIConnectNotImplementedError } from "@ag-ui/core";
17-
import { Middleware, MiddlewareFunction, FunctionMiddleware } from "@/middleware";
17+
import {
18+
Middleware,
19+
MiddlewareFunction,
20+
FunctionMiddleware,
21+
BackwardCompatibility_0_0_39,
22+
} from "@/middleware";
1823
import packageJson from "../../package.json";
1924

2025
export interface RunAgentResult {
@@ -48,7 +53,12 @@ export abstract class AbstractAgent {
4853
this.messages = structuredClone_(initialMessages ?? []);
4954
this.state = structuredClone_(initialState ?? {});
5055
this.debug = debug ?? false;
51-
parseSemanticVersion(this.maxVersion);
56+
57+
const parsedMaxVersion = parseSemanticVersion(this.maxVersion);
58+
59+
if (parsedMaxVersion.compare(parseSemanticVersion("0.0.39")) <= 0) {
60+
this.middlewares.unshift(new BackwardCompatibility_0_0_39());
61+
}
5262
}
5363

5464
public subscribe(subscriber: AgentSubscriber) {
@@ -62,7 +72,6 @@ export abstract class AbstractAgent {
6272

6373
abstract run(input: RunAgentInput): Observable<BaseEvent>;
6474

65-
6675
public use(...middlewares: (Middleware | MiddlewareFunction)[]): this {
6776
const normalizedMiddlewares = middlewares.map((middleware) =>
6877
typeof middleware === "function" ? new FunctionMiddleware(middleware) : middleware,
@@ -71,7 +80,6 @@ export abstract class AbstractAgent {
7180
return this;
7281
}
7382

74-
7583
public async runAgent(
7684
parameters?: RunAgentParameters,
7785
subscriber?: AgentSubscriber,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { Middleware, FunctionMiddleware } from "./middleware";
22
export type { MiddlewareFunction } from "./middleware";
33
export { FilterToolCallsMiddleware } from "./filter-tool-calls";
4+
export { BackwardCompatibility_0_0_39 } from "./backward-compatibility-0-0-39";

sdks/typescript/packages/client/src/utils.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ export interface ParsedSemanticVersion {
2727
prerelease: string[];
2828
build: string[];
2929
source: string;
30+
compare(other: ParsedSemanticVersion): number;
3031
}
3132

3233
const SEMVER_PATTERN =
3334
/^(?<major>0|[1-9]\d*)(?:\.(?<minor>0|[1-9]\d*)(?:\.(?<patch>0|[1-9]\d*))?)?(?:-(?<prerelease>(?:0|[1-9A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))*))?(?:\+(?<build>[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
35+
const NUMERIC_IDENTIFIER_PATTERN = /^\d+$/;
3436

3537
/**
3638
* Parses a semantic version string into its numeric components.
@@ -56,12 +58,79 @@ export function parseSemanticVersion(version: string): ParsedSemanticVersion {
5658
const prerelease = match.groups.prerelease ? match.groups.prerelease.split(".") : [];
5759
const build = match.groups.build ? match.groups.build.split(".") : [];
5860

59-
return {
61+
const parsed: ParsedSemanticVersion = {
6062
major,
6163
minor,
6264
patch,
6365
prerelease,
6466
build,
6567
source: version,
68+
compare(this: ParsedSemanticVersion, other: ParsedSemanticVersion): number {
69+
if (this.major !== other.major) {
70+
return this.major - other.major;
71+
}
72+
73+
if (this.minor !== other.minor) {
74+
return this.minor - other.minor;
75+
}
76+
77+
if (this.patch !== other.patch) {
78+
return this.patch - other.patch;
79+
}
80+
81+
if (this.prerelease.length === 0 && other.prerelease.length === 0) {
82+
return 0;
83+
}
84+
85+
if (this.prerelease.length === 0) {
86+
return 1;
87+
}
88+
89+
if (other.prerelease.length === 0) {
90+
return -1;
91+
}
92+
93+
const length = Math.max(this.prerelease.length, other.prerelease.length);
94+
for (let index = 0; index < length; index++) {
95+
const aIdentifier = this.prerelease[index];
96+
const bIdentifier = other.prerelease[index];
97+
98+
if (aIdentifier === undefined) {
99+
return -1;
100+
}
101+
102+
if (bIdentifier === undefined) {
103+
return 1;
104+
}
105+
106+
const aIsNumeric = NUMERIC_IDENTIFIER_PATTERN.test(aIdentifier);
107+
const bIsNumeric = NUMERIC_IDENTIFIER_PATTERN.test(bIdentifier);
108+
109+
if (aIsNumeric && bIsNumeric) {
110+
const diff = Number(aIdentifier) - Number(bIdentifier);
111+
if (diff !== 0) {
112+
return diff;
113+
}
114+
continue;
115+
}
116+
117+
if (aIsNumeric) {
118+
return -1;
119+
}
120+
121+
if (bIsNumeric) {
122+
return 1;
123+
}
124+
125+
const lexicalComparison = aIdentifier.localeCompare(bIdentifier);
126+
if (lexicalComparison !== 0) {
127+
return lexicalComparison;
128+
}
129+
}
130+
131+
return 0;
132+
},
66133
};
134+
135+
return parsed;
67136
}

0 commit comments

Comments
 (0)