Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: middleware for agentica #64

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
Draft

feat: middleware for agentica #64

wants to merge 11 commits into from

Conversation

kakasoo
Copy link
Contributor

@kakasoo kakasoo commented Feb 28, 2025

This PR improves the documentation for the use method to better describe its role in registering middlewares. The updated comment clarifies execution order, next() handling, and async considerations, making it more suitable for developers using this API.

by the way, I'm still thinking about the best way to handle middleware order. What do you all think? 🤔

@kakasoo kakasoo self-assigned this Feb 28, 2025
@sunrabbit123
Copy link
Collaborator

is it draft?

i think that first registered middleware should first execute

@kakasoo
Copy link
Contributor Author

kakasoo commented Feb 28, 2025

Yes, you are right. I will change its ordering.

});

agent.use(async function middleware_three(_ctx, next) {
i = i - 1; // 3
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please write additional test for to test after called next()

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too

usage: this.token_usage_,
}),
);
const middlewares = this.middlewares_.get("conversate" as const);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend this "conversate" string literal convert string literal constant variable

* - If not called, the current middleware will act as a termination point.
*/
next: () => Promise<void>,
) => any;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this return value should be a Awaitable<void>
if return type is any, it means that it is being used somewhere

})(context, async () => {});
}

const newbie: IAgenticaPrompt[] = await this.executor_(context);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

middleware should cover reqeust and response
but, current architecture can't cover response

nextjs:
https://nextjs.org/docs/app/building-your-application/routing/middleware

if user can use next(), it means cover request and response

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added a comment about this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reason why we chose next() is because of to manage before process and after process.
however, the current middleware runs before the process.

For the previous process, we should not use the next() keyword as it confuses clients.

@kakasoo kakasoo requested a review from sunrabbit123 February 28, 2025 09:50
usage: this.token_usage_,
}),
);
const CONVERSATE = "conversate" as const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this constant variable should exsits outer

*/
use(middleware: Middleware): void;
public use(middleware: Middleware) {
const type = "conversate" as const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

})(context, async () => {});
}

const newbie: IAgenticaPrompt[] = await this.executor_(context);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reason why we chose next() is because of to manage before process and after process.
however, the current middleware runs before the process.

For the previous process, we should not use the next() keyword as it confuses clients.

});

agent.use(async function middleware_three(_ctx, next) {
i = i - 1; // 3
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too

@kakasoo
Copy link
Contributor Author

kakasoo commented Mar 4, 2025

@sunrabbit123

{
  ...
  public async conversate(content: string): Promise<IAgenticaPrompt[]> {
    const prompt: IAgenticaPrompt.IText<"user"> = {
      type: "text",
      role: "user",
      text: content,
    };
    await this.dispatch(prompt);
    const context = this.getContext({ prompt, usage: this.token_usage_ });

    
    const newbie: IAgenticaPrompt[] = await this.executor_(context);
    this.prompt_histories_.push(prompt, ...newbie);
    const middlewares = this.middlewares_.get(CONVERSATE);
    if (middlewares) {
      await Array.from(middlewares).reduce((acc, cur) => {
        return this.middlewareCompose(acc, cur);
      })(context, async () => {});
    }
    return [prompt, ...newbie];
  }
  ...
}

Do you think should be after execute like this? @sunrabbit123

@sunrabbit123
Copy link
Collaborator

sunrabbit123 commented Mar 4, 2025

I think the executor should be executed innermost.
image

middleware should not be run twice

@kakasoo
Copy link
Contributor Author

kakasoo commented Mar 4, 2025

image

Like this?

@sunrabbit123
Copy link
Collaborator

sunrabbit123 commented Mar 4, 2025

middleware should process both before and after

so, example

const layer = this.middlewares_.get(CONVERSTAE) ?? [];
layer.push(this._executor);
const newbie = await Array.from(layer)
  .reduce((acc, cur) => this.middlewareCompose(acc, cur))(context, async () => {});

@kakasoo
Copy link
Contributor Author

kakasoo commented Mar 4, 2025

middleware should process both before and after

so, example

const layer = this.middlewares_.get(CONVERSTAE) ?? [];
layer.push(this._executor);
const newbie = await Array.from(layer)
  .reduce((acc, cur) => this.middlewareCompose(acc, cur))(context, async () => {});

I don't understand if middleware can be processed before and after execution in your code. Isn't this the act of seeing the final execution as one of the middleware and just putting execute in the end?

@kakasoo
Copy link
Contributor Author

kakasoo commented Mar 4, 2025

I've heard explanations from you. The functional form is profound. But I understand it perfectly.

@sunrabbit123 sunrabbit123 changed the title middleware for agentica feat: middleware for agentica Mar 7, 2025
@sunrabbit123
Copy link
Collaborator

Temporary stops

@sunrabbit123 sunrabbit123 marked this pull request as draft March 7, 2025 10:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants